康康舞的技巧怎么写才能这么可以?和accessible_by 都适用于自引用HABTM 关系?
我对如何使用自引用 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 返回正确的数据集,但随后 can?(:read, video) 对于该结果集中的视频会导致运行时错误。
NoMethodError: undefined method `parent_channels_channels.name' for #<Channel:0x007fef35593748>
如何指定此功能,使其与 can? 和 accessible_by 一起使用?
I am stumped on how to handle this situation using a self referencing HABTM relation, cancan, and ActiveRecord.
I am trying to use accessible_by to determine a set of videos that are visible given a relationship between videos and channels, but the resulting SQL has the wrong table name for part of the query. Here are the relationships:
# 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.
I need a cancan ability to find all public videos that are in public sub-channels of the default channel. I tried the following:
# ability.rb
can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {:name => "Default"}}
In the console, when I try this out, I get the following:
> 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'
=> []
I have some records in place that should result in a video, and, more to the point, would have expected the end of the query to have "parent_channels_channels"."name" = 'Default', but the table is "channels" in stead, resulting in the wrong dataset since the SQL is referencing the name of the channel, not the parent channel.
I tried changing the ability as follows to force the table name:
can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {"parent_channels_channels.name" => "Default"}}
That results in the correct query, and accessible_by returns the right dataset, but then can?(:read, video) for a video in that result set results in a runtime error.
NoMethodError: undefined method `parent_channels_channels.name' for #<Channel:0x007fef35593748>
How do I specify this ability so it works with both can? and accessible_by?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从您的代码中我不清楚您是否正确建模。你真的希望parent_channels和subchannels是HABTM关系,甚至是同一个模型吗?也许您的应用程序中的一些实际示例会对我有所帮助,但您似乎想要的是父 VideoCategory,并且您希望 HABTM 与频道之间的关系,然后每个频道与视频都有一个 has_many 关系。
然后,您可以让 VideoCategory 具有 has_many :videos, :through => :渠道关系。
看起来您正试图使 Channel 类不仅仅成为一个频道。父母和孩子的概念在习惯关系中没有多大意义。一般来说,如果您想要一个父类和子类,那么您需要一对多的关系。多对多意味着这两个关联都不是父类(当然,这可能与您在 UI 中呈现它的方式不同)。
如果您确实必须这样做作为自我引用,您是否尝试过使用范围来代替?
看来,将逻辑放入作用域并置于能力之外可能会帮助您更好地控制所编写的 SQL 内容——它消除了 CanCan 正在做的抽象层。
It's not clear to me from your code whether you are modelling this correctly. Do you really want parent_channels and subchannels to be a HABTM relationship, or even be the same model? Maybe some real-world examples from your app would help me here but it seems like what you want is a parent VideoCategory, and you want HABTM relationships with Channels, which then each have a has_many relationship with videos.
You could then have VideoCategory having a has_many :videos, :through => :channels relationship.
It seems like you are trying to make the Channel class do more than be a channel. The concept of parents and children doesn't make a lot of sense in habtm relationships. Generally if you want a parent class and sub classes, then you want a 1-to-many relationship. Many-to-many implies that neither association is the parent class (although this may be different than how you present it in the UI, of course).
If you really must do this as self-referential, have you tried using scopes instead?
It seems that putting the logic into scopes and out of ability.rb might help you better control exactly what SQL gets written -- it removes the layer of abstraction that CanCan is doing.