我很难理解如何使用自引用HABTM关系,cancan和ActiveRecord来处理这种情况。
我正在尝试使用 accessible_by 来确定一组视频,这些视频在视频和频道之间存在关系时可见,但生成的SQL的部分查询表名称错误。以下是关系:
# video.rb
class Video < ActiveRecord::Base
belongs_to :channel
end
# channel.rb
class Channel < ActiveRecord::Base
has_many :videos
has_and_belongs_to_many :subchannels, :class_name => "Channel", :join_table => "channels_channels", :foreign_key => :parent_id, :association_foreign_key => :subchannel_id
has_and_belongs_to_many :parent_channels, :class_name => "Channel", :join_table => "channels_channels", :foreign_key => :subchannel_id, :association_foreign_key => :parent_id
end
# The appropriate channels_channels table exists with subchannel_id and parent_id fields.
我需要 cancan能力来查找默认频道的公共子频道中的所有公开视频。我尝试了以下方法:
# ability.rb
can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {:name => "Default"}}
在控制台中,当我尝试这个时,我得到以下内容:
> Video.accessible_by(Ability.new(nil))
SELECT "videos".* FROM "videos" INNER JOIN "channels" ON "channels"."id" = "videos"."channel_id" INNER JOIN "channels_channels" ON "channels_channels"."subchannel_id" = "channels"."id" INNER JOIN "channels" "parent_channels_channels" ON "parent_channels_channels"."id" = "channels_channels"."parent_id" WHERE "videos"."permission" = 'public' AND "channels"."permission" = 'public' AND "channels"."name" = 'Default'
=> []
我有一些应该会产生视频的记录,而且更重要的是,预计查询的结尾会有“parent_channels_channels”。“name”='Default',但表格是“channels”,导致错误的数据集,因为SQL引用了通道的名称,而不是父通道。
我尝试按如下方式更改功能以强制使用表名:
can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {"parent_channels_channels.name" => "Default"}}
这会产生正确的查询,而 accessible_by 会返回正确的数据集,但可以?(:读取,视频)表示该结果集中的视频会导致运行时错误。
NoMethodError: undefined method `parent_channels_channels.name' for #<Channel:0x007fef35593748>
如何指定此功能,以便它与可以?和 accessible_by 一起使用?
答案 0 :(得分:0)
我从您的代码中不清楚您是否正确建模。你真的希望parent_channels和subchannels成为HABTM关系,甚至是同一个模型吗?也许你的应用程序中的一些真实世界的例子会对我有帮助,但看起来你想要的是一个父视频类别,你想要与频道的HABTM关系,然后每个频道都与视频有一个很好的关系。
然后你可以让VideoCategory有一个has_many:videos,:through =&gt; :渠道关系。
class VideoCategory
has_and_belongs_to_many :channels
has_many :videos, :through => :channels
end
class Video
belongs_to :channel
end
class Channel
has_many :videos
has_and_belongs_to_many :video_cateogories
end
看起来你正试图让Channel类不仅仅是一个频道。父母和孩子的概念在habtm关系中没有多大意义。通常,如果您需要父类和子类,则需要1对多关系。多对多意味着两个关联都不是父类(当然,这可能与您在UI中呈现它的方式不同)。
如果你真的必须这样做,那么你是否尝试过使用范围呢?
class Video
scope :public, lambda do
joins(:channel).where("videos.permission = 'public' and channels.permission = 'public'")
end
end
似乎将逻辑放入范围并且没有能力.rb可能有助于您更好地控制SQL编写的内容 - 它删除了CanCan正在进行的抽象层。