Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 使用HMABTM验证所有权的最佳方法_Ruby On Rails_Validation_Activerecord_Has And Belongs To Many - Fatal编程技术网

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:通过明天的
,我希望不使用它,因为我不需要中间模型