2011-12-23 17 views
5

Tôi đang bối rối về cách xử lý tình huống này bằng cách sử dụng mối quan hệ tự tham chiếu HABTM, cancan và ActiveRecord.Làm thế nào để bạn viết một khả năng cancan để có thể? và accessible_by cả hai có thể tự nghiên cứu mối quan hệ HABTM hay không?

Tôi đang cố gắng sử dụng accessible_by để xác định tập hợp video hiển thị cho mối quan hệ giữa video và kênh nhưng SQL kết quả có tên bảng sai cho một phần truy vấn. Dưới đây là các mối quan hệ:

# 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. 

Tôi cần một khả năng Cancan để tìm tất cả video công cộng mà là ở nơi công cộng phụ kênh của kênh mặc định. Tôi thử như sau:

# ability.rb 
can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {:name => "Default"}} 

Trong giao diện điều khiển, khi tôi cố gắng này ra, tôi nhận được như sau:

> 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' 
=> [] 

Tôi có một số hồ sơ ở nơi đó nên kết quả trong một đoạn video, và nhiều hơn nữa đến thời điểm này, sẽ có kết thúc truy vấn có "parent_channels_channels". "name" = 'Mặc định', nhưng bảng là "kênh" thay vào đó, dẫn đến tập dữ liệu sai do SQL đang tham chiếu tên kênh, không phải kênh chính.

tôi đã cố gắng thay đổi khả năng như sau để buộc các tên bảng:

can :read, Video, :permission => 'public', :channel => {:permission => 'public', :parent_channels => {"parent_channels_channels.name" => "Default"}} 

Đó là kết quả trong truy vấn chính xác, và accessible_by trả về tập dữ liệu đúng, nhưng sau đó lon (: đọc, video) cho một video trong tập hợp kết quả đó dẫn đến lỗi thời gian chạy.

NoMethodError: undefined method `parent_channels_channels.name' for #<Channel:0x007fef35593748> 

Làm cách nào để chỉ định khả năng này để hoạt động với cả hai có thể?accessible_by?

Trả lời

0

Nó không rõ ràng với tôi từ mã của bạn cho dù bạn đang mô hình hóa một cách chính xác. Bạn có thực sự muốn parent_channels và subchannels là một mối quan hệ HABTM, hoặc thậm chí là cùng một mô hình? Có thể một số ví dụ trong thế giới thực từ ứng dụng của bạn sẽ giúp tôi ở đây nhưng có vẻ như những gì bạn muốn là VideoCategory gốc và bạn muốn mối quan hệ HABTM với Kênh, mỗi kênh có mối quan hệ has_many với video.

Sau đó, bạn có thể có VideoCategory có mối quan hệ has_many: video,: through =>: channels.

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 

Có vẻ như bạn đang cố gắng làm cho lớp kênh hoạt động nhiều hơn là một kênh. Khái niệm về cha mẹ và trẻ em không có nhiều ý nghĩa trong các mối quan hệ habtm. Nói chung nếu bạn muốn có một lớp cha và các lớp con, thì bạn muốn có một mối quan hệ 1-nhiều. Nhiều người cho rằng không có liên kết nào là lớp cha (mặc dù điều này có thể khác với cách bạn thể hiện nó trong giao diện người dùng).

Nếu bạn thực sự phải làm điều này là tự tham chiếu, bạn đã thử sử dụng phạm vi thay thế chưa?

class Video 
    scope :public, lambda do 
    joins(:channel).where("videos.permission = 'public' and channels.permission = 'public'") 
    end 
end 

Dường như đưa logic vào phạm vi và ngoài khả năng.rb có thể giúp bạn kiểm soát chính xác hơn những gì SQL được viết - nó loại bỏ lớp trừu tượng mà CanCan đang làm.

Các vấn đề liên quan