以下是我的模型:
class User < ApplicationRecord
has_many :cities_users, inverse_of: :user
has_many :cities, through: :cities_users
accepts_nested_attributes_for :cities_users
end
class CitiesUser < ApplicationRecord
belongs_to :user
belongs_to :city
validates :user_id, uniqueness: { scope: :city_id, message: "already specified that they have lived in this city"}
end
class City < ApplicationRecord
has_many :cities_users
has_many :users, through: :cities_users
end
创建新的user
记录时:用户可以动态添加他们所居住的城市(通过nested_form_fields gem)。这最终会在cities_users
的连接表上创建记录。
点击“添加您居住的城市”之后&#39;按钮:
用户然后再次点击该按钮以添加其他城市:
上面的情况是我希望在用户点击Create User
按钮时触发验证错误的地方。创建新用户记录时:用户不应指定他们多次居住在同一个城市。
如上所述:未经验证:将使用相同的cities_users
和user_id
创建两个 city_id
条记录。这不好,所以我想重新渲染表单,突出显示两个有问题的cities_users
嵌套字段,并有一条错误消息说出&#34;你不能指定用户已经住在同一个城市更多比一次&#34;。
显然,这需要在user
模型或cities_user
模型上进行验证。我不知道验证应该去哪里,我不知道如何编写验证代码以便它捕获此错误。我在uniqueness
模型上的当前CitiesUser
验证没有发现这种情况。
额外的设置信息,以防万一有人想要重新创建场景
这就是我在用户_form.html.erb
中设置nested_fields的方式:
<%= f.nested_fields_for :cities_users do |ff| %>
<div>
<%= ff.label :city_id %>
<%= ff.collection_select(:city_id, City.all, :id, :name) %>
</div>
<% end %>
<br>
<div><%= f.add_nested_fields_link :cities_users, "Add a City You have lived in" %></div>
users_controller#create
操作是标准的,由scaffold
命令生成。我确实添加了强大的参数,以便允许嵌套属性:
def user_params
params.require(:user).permit(:name, cities_users_attributes: [:id, :city_id, :user_id])
end
答案 0 :(得分:1)
我认为最好的办法就是在user_params方法中将其传递给User模型,这是在User模型中添加自定义验证。强制他们添加的城市的ID在通过&#39; id&#39;提交的城市数组中是唯一的。做类似的事情:
class User < ActiveRecord::Base
validate :no_duplicate_cities
#I'm assuming user_cities is an array of city id's so we only want one id of each different city at most.
def no_duplicate_cities
self.user_cities = self.user_cities.uniq
end
这只会在该数组中保留唯一ID,从而删除任何重复的城市。
答案 1 :(得分:1)
我终于做到了这一点:
#models/user.rb
class User < ActiveRecord::Base
has_many :cities_users
has_many :cities, through: :cities_users
accepts_nested_attributes_for :cities_users, allow_destroy: true
validate :no_duplicate_cities
private
def no_duplicate_cities
errors.add(:duplicate_cities, "are present") if self.cities_users.group_by(&:city_id).values.detect{|arr| arr.size > 1}
end
end
答案 2 :(得分:0)
我在我的应用程序中做了类似的事情,在用户模型中尝试以下代码。
validate :unique_cities
def unique_cities
unless self.user_cities.map(&:city_id).uniq
errors.add(:cites, "- can not be 2 of the same cities")
end
end