4

モデルを次のように設定しました(再販業者のために保存したい情報は、そのテーブルのすべてのフィールドをミラーリングし、既存のデータ構造を使用するために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によって記述されたセットに一致するすべての連絡先を管理できるようにしたいと思います。

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))

カンカンについての私の理解は、それが許可されているものと許可されていないものを連絡先ごとにチェックするということです。ブロック内でやりたいことができれば、次のように表示されます(リセラー自身の連絡先とリセラーのクライアントであるすべての連絡先の両方をカバーします)。

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)

編集:

ほとんど解決しましたが、今は能力を組み合わせるという問題があります。

アビリティモデルの作業部分を次のように変更しました。

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行が2番目の行で上書きされることです。私はそれらが置き換えではなく、付加的であるべきだという印象を受けました。さらに調査が必要ですが、この質問自体は上記で解決されたと思います。次に、両方のcan :manage行を適用する方法を検討する必要があります。

4

2 に答える 2

8

2015年3月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

ディーフォー、途中であなたの助けに感謝します、あなたのコメントなしで私がそこに着いたとは思わないでください。

于 2012-07-12T21:40:00.230 に答える
1

私はあなたがまだあなたができるほど明確にあなたの要求を表現していないと思います

...リセラー自身の連絡先のID

:resellerContactContactです。:contactに属性はありませんContact。おそらく、クラスの関連付けとの混同を避けるために、(クラスからの)ユーザーを参照する必要があるときに、「再販業者の役割」と「再販業者」を参照することCanCanContact:resellerで、混乱を招きます。

私は仮定します

reseller_idフィールドがリセラー自身の連絡先のIDに設定されているすべての連絡先を管理できるようにするリセラーの役割。

意味する

userいくつかの連絡先のContact cどこc.reseller_idにあるかを管理できますuser_iduser.contacts

これが正確な解釈であると仮定すると:

can :manage, Contact do |c|
  user.contacts.where(:user_id => c.reseller_id)
end
于 2012-07-12T12:57:58.387 に答える