Ruby on rails 使用HMABTM验证所有权的最佳方法
我有三个这样的模型:Ruby on rails 使用HMABTM验证所有权的最佳方法,ruby-on-rails,validation,activerecord,has-and-belongs-to-many,Ruby On Rails,Validation,Activerecord,Has And Belongs To Many,我有三个这样的模型: class User < ActiveRecord::Base has_many :items has_many :other_itmes end class Item < ActiveRecord::Base belongs_to :user has_and_belongs_to_many :other_items validate :validate_other_item_ownership def validate_other_
class User < ActiveRecord::Base
has_many :items
has_many :other_itmes
end
class Item < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :other_items
validate :validate_other_item_ownership
def validate_other_item_ownership
if
(user_ids = OtherItem.where(id: other_item_ids).pluck(:user_id).uniq).present? &&
(user_ids.size > 1 || user_ids.first != user_id)
then
errors.add(:other_item_ids, 'Other Items must belong to same user as Item')
end
end
end
class OtherItem < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :items
validate :validate_item_ownership
def validate_item_ownership
if
(user_ids = Item.where(id: item_ids).pluck(:user_id).uniq).present? &&
(user_ids.size > 1 || user_ids.first != user_id)
then
errors.add(:item_ids, 'Items must belong to same user as Other Item')
end
end
end
class ItemsController < ApplicationController
def update
@item = Item.find params[:id]
@item.other_item_ids = params[:item][:other_item_ids] #assignline
@item.save!
end
end
class OtherItemsController < ApplicationController
def update
@other_item = OtherItem.find params[:id]
@other_item.item_ids = params[:other_item][:item_ids] #assignline
@other_item.save!
end
end
class用户1 | | user_id.first!=user_id)
然后
错误。添加(:other_item_id,“other item必须与item属于同一用户”)
结束
结束
结束
类OtherItem1 | | user_id.first!=user_id)
然后
错误。添加(:item_id,'项必须与其他项属于同一用户')
结束
结束
结束
两个控制器如下:
class User < ActiveRecord::Base
has_many :items
has_many :other_itmes
end
class Item < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :other_items
validate :validate_other_item_ownership
def validate_other_item_ownership
if
(user_ids = OtherItem.where(id: other_item_ids).pluck(:user_id).uniq).present? &&
(user_ids.size > 1 || user_ids.first != user_id)
then
errors.add(:other_item_ids, 'Other Items must belong to same user as Item')
end
end
end
class OtherItem < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :items
validate :validate_item_ownership
def validate_item_ownership
if
(user_ids = Item.where(id: item_ids).pluck(:user_id).uniq).present? &&
(user_ids.size > 1 || user_ids.first != user_id)
then
errors.add(:item_ids, 'Items must belong to same user as Other Item')
end
end
end
class ItemsController < ApplicationController
def update
@item = Item.find params[:id]
@item.other_item_ids = params[:item][:other_item_ids] #assignline
@item.save!
end
end
class OtherItemsController < ApplicationController
def update
@other_item = OtherItem.find params[:id]
@other_item.item_ids = params[:other_item][:item_ids] #assignline
@other_item.save!
end
end
class ItemsController
现在的问题是ActiveRecord已经在#assignline
上保存了项目,而调用#save
正确引发ActiveRecord::RecordInvalid
关联仍然保持
我只希望用户能够链接到他所拥有的项目。好问题!我也得到了一个很好的答案;) (TLDR)Ditch
has_和_属于_many
,在联接表顶部创建一个模型,将验证逻辑放入联接模型中,然后使用has_many:至
为了论证,我们来考虑艺术家和歌曲之间的关系,两者都属于用户。通过join模型和有很多:通过我们将有以下模型类:
class Artist
belongs_to :user
has_many :artist_songs
has_many :songs, through: :artist_songs
end
class Song
belongs_to :user
has_many :artist_songs
has_many :artists, through: :artist_songs
end
class ArtistSong
belongs_to :artist
belongs_to :song
end
这将大大清理您的验证逻辑,只需将其添加到一个位置:
class ArtistSong
#...
validate :ownership
private
def ownership
unless artist.user_id == song.user_id
errors[:base] << 'artist and song must belong to same user'
end
end
end
注意:看起来Rails正在执行保存连接模型上的代码>。这意味着如果验证失败(仅在ArtistSong
,而不是Artist
),它将引发异常而不是返回false。这应该只发生在恶意用户身上,所以不用担心
我很少使用HABTM。拥有一个连接表模型可以提供更大的灵活性。例如,您可以添加一个“职位”字段并执行以下操作:
class Artist
#...
has_many :artist_songs, order: -> {'position asc'}
#...
end
对于
,使用接受嵌套的属性如何?我不想/需要接受属性,因为我不更新/创建任何(其他)项
。我想做的就是将多个项目
与其他项目
关联起来,反之亦然。但只允许同一用户拥有的模型之间的关系(有效)!验证器不应该返回false吗?也许从habtm切换到HASU MUN THRON可以解决这个问题。您可以对连接模型进行验证,然后验证程序不需要返回false,它必须添加一个错误,然后验证失败。我将尝试使用has_many:通过明天的,我希望不使用它,因为我不需要中间模型