我的模型设置如下(联系人中的自我关联,因为我想为经销商存储的信息镜像该表中的所有字段,似乎与DRY保持一致以使用现有的数据结构):
class Contact < ActiveRecord::Base
attr_accessible :reseller_id
has_and_belongs_to_many :users
has_many :reseller_clients, :class_name => "Contact", :foreign_key => "reseller_id"
belongs_to :reseller, :class_name => "Contact"
end
class User < ActiveRecord::Base
attr:accessible :name
has_and_belongs_to_many :contacts
end
使用cancan,我想拥有一个能够管理自己联系人的经销商登录。用户和经销商之间的映射是HABTM,因此可以通过执行以下can :manage Contact, :users => {:id => user.id}
来实现。
我还希望经销商登录能够在以下逻辑中管理与managed_accounts描述的集合匹配的所有Contact:
reseller_contacts = user.contacts
managed_accounts = []
reseller_contacts.each do |i|
managed_accounts << i.reseller_clients
end
managed_accounts.flatten!
我目前的能力课程有:
class Ability
include CanCan::Ability
def initialize(user)
if user.role? :reseller
# Allow resellers to manage their own Contact
can :manage, Contact, :users => {:id => user.id} # This works correctly at present
# Allow resellers to manage their client Contacts
can :manage, Contact, :reseller => {:users => {:id => user.id}} #This doesn't work
end
end
end
我收到的错误原样如下:
Mysql2::Error: Unknown column 'contacts.users' in 'where clause': SELECT `contacts`.* FROM `contacts` INNER JOIN `contacts` `resellers_contacts` ON `resellers_contacts`.`id` = `contacts`.`reseller_id` INNER JOIN `contacts_users` ON `contacts_users`.`contact_id` = `resellers_contacts`.`id` INNER JOIN `users` ON `users`.`id` = `contacts_users`.`user_id` INNER JOIN `contacts_users` `users_contacts_join` ON `users_contacts_join`.`contact_id` = `contacts`.`id` INNER JOIN `users` `users_contacts` ON `users_contacts`.`id` = `users_contacts_join`.`user_id` WHERE ((`contacts`.`users` = '---\n:id: 6\n') OR (`users`.`id` = 6))
我对cancan的理解是它根据每个联系人检查什么是允许的和不允许的。如果我可以在一个区块中执行我想要的操作,它将显示如下(涵盖经销商自己的联系人以及作为经销商客户的所有联系人):
can :manage, Contact do |contact|
user.contacts.exists?(contact.reseller_id) || user.contacts.exists?(contact.id)
end
我不能使用一个块,因为当我在控制器上的索引操作中尝试使用@contacts = Contact.accessible_by(current_ability)
时,我得到:
The accessible_by call cannot be used with a block 'can' definition. The SQL cannot be determined for :index Contact(id: integer, first_name: string, last_name: string, postal_addr_line_1: string, postal_addr_line_2: string, postal_addr_line_3: string, postal_addr_city: string, postal_addr_post_code: string, postal_addr_country: string, billing_addr_line_1: string, billing_addr_line_2: string, billing_addr_line_3: string, billing_addr_city: string, billing_addr_post_code: string, billing_addr_country: string, contact_email: string, company_name: string, phone_home: string, phone_work: string, phone_mobile: string, split_bills: boolean, created_at: datetime, updated_at: datetime, reseller_id: integer)
几乎已经解决了,现在我遇到了一个组合能力的问题:
我将Ability模型的工作部分改为:
reseller_contacts = user.contacts
managed_accounts = []
reseller_contacts.each do |i|
i.reseller_clients.each do |rc|
managed_accounts << rc.id
end
end
can :manage, Contact, :id => managed_accounts
can :manage, Contact, :users => {:id => user.id}
can :create, Contact
现在唯一的问题是第一条can :manage
线会被第二条线覆盖。我的印象是它们应该是添加剂,而不是替代品。需要更多的研究,但我认为这个问题本身是由上述问题解决的。现在我需要弄清楚如何应用can :manage
行。
答案 0 :(得分:8)
编辑2015-03-26
注意到这个问题/答案得到了一些关注,我想我应该指出一个我以后找到的更好的方法。
创建has_one / has_many关联时,rails分别创建foreign_model_id
/ foreign_model_ids
方法。这些方法分别返回整数或整数数组。
这意味着代替下面的答案,ability.rb
文件中的条目可以简化,而不必使用那个丑陋的逻辑来创建我自己的对象数组并迭代它们:
can :manage, Contact, id: (user.contact_ids + user.reseller_client_ids)
为后代保留以前的答案
通过在Ability.rb文件中使用它来修复:
# Manage all contacts associated to this reseller
reseller_contacts = user.contacts
managed_contacts = []
reseller_contacts.each do |i|
i.reseller_clients.each do |rc|
managed_contacts << rc.id
end
managed_contacts << i.id
end
can :manage, Contact, :id => managed_contacts
Deefour,感谢你一路走来的帮助,如果没有你的意见,我不会认为我会去那儿。
答案 1 :(得分:1)
我认为你仍然没有尽可能清楚地写下你的要求
...经销商自己的联系人ID
:reseller
的{{1}}是另一个Contact
。 Contact
中没有:contact
个属性。当您应该引用用户(来自Contact
类)以避免与{{1混淆时“时,您可能会通过引用”经销商角色“和”经销商“来让事情变得混乱类'CanCan
关联)。
我会假设
代理商角色,可以管理将reseller_id字段设置为代理商自己的联系人ID的所有联系人。
表示
中某些联系人的
Contact
可以管理:reseller
user
,其中Contact
是c
c.reseller_id
假设这是一个准确的解释:
user_id