3

私はここで他の多くのトピック(1、2、3 ...)を読みましたどれ私の問題を本当に解決しませんでした。

これが私の3つのモデルです。

User
  has_many :memberships
  has_many :accounts, :through => :memberships
  accepts_nested_attributes_for :memberships
end

Account
  has_many :memberships
  has_many :users, :through => :memberships
  accepts_nested_attributes_for :memberships
end

Membership
  attr_accessible :account_id, :url, :user_id
  belongs_to :account
  belongs_to :user
end

ご覧のとおり、私の参加モデルのメンバーシップには追加の属性があります:url

アカウントテーブルには、GitHub、Stack Overflow、Twitter、Facebook、LinkedInなどのオンラインサービスの名前を保存しています。合計で9つあります。これは、私が頻繁に更新する傾向のない一定量のアカウントです。

ユーザーフォームで、これを作成したいと思います。

ユーザーネストフォーム

これらのフィールドのいずれかに入力された値は、次の3つの値を使用して、Membershipsテーブルにのみ送信する必要があります。

  • url(テキストフィールドに入力された値)
  • user_id(現在のユーザーフォームのID)
  • account_id(関連するアカウントのID、たとえばLinkedInは「5」です)

私は3つのオプションを試しました。それらはすべて機能しますが、部分的にしか機能しません。

オプション1

<% for account in @accounts %>
  <%= f.fields_for :memberships do |m| %>
    <div class="field">
      <%= m.label account.name %><br>
      <%= m.text_field :url %>
    </div>
  <% end %>
<% end %>

アカウントごとに1つずつ、合計9つのテキストフィールドが必要です。そこで、アカウントをループして、メンバーシップモデルに関連するURLフィールドを作成します。

初めてフィールドが正しく表示されますが、次回は81フィールドが表示されます。

ループの問題

オプション#2

<% @accounts.each do |account| %>
  <p>
    <%= label_tag(account.name) %><br>
    <%= text_field_tag("user[memberships_attributes][][url]") %>
    <%= hidden_field_tag("user[memberships_attributes][][account_id]", account.id) %>
    <%= hidden_field_tag("user[memberships_attributes][][user_id]", @user.id) %>
  </p>
<% end %>

メンバーシップテーブルの各列に3つの値を手動で入力しようとしています。

それは動作しますが:

  • アカウントとユーザーIDの両方を表示することはあまり安全ではないようです(いいえ?)
  • ユーザーを編集するたびにフィールドがリセットされます
  • 送信ごとに値が複製されます

オプション#3(これまでで最高のもの)

<%= f.fields_for :memberships do |m| %>
  <div class="field">
    <%= m.label m.object.account.name %><br>
    <%= m.text_field :url %>
  </div>
<% end %>

メンバーシップモデル用に、ユーザーフォームにネストされたフォームを作成しています。

それはほぼ完全に機能します:

  • アカウントごとに1つずつ、正確に9つのフィールド
  • 重複はありません

ただし、Membershipsテーブルがすでに入力されている場合にのみ機能します。(たとえば、オプション#2を使用)。

そこで、UsersControllerを使用していくつかのインスタンスを構築してみました。

if (@user.memberships.empty?)
  @user.memberships.build
end

しかし、m.labelm.object.account.name行でこのエラーが発生します。

undefined method `name' for nil:NilClass

とにかく、私はおそらくここでモデルを通してhas_manyについて何かが欠けています。has_and_belongs_to_manyアソシエーションを作成できましたが、ここでは、3番目のモデル(アカウント)に関する情報を使用して、最初のモデル(ユーザー)を介してその結合モデル(メンバーシップ)に取り組みたいと思います。

よろしくお願いします。ありがとうございました。

4

2 に答える 2

2

次のデータ設計アプローチを使用します。システム内のすべてのユーザーは、すべての可能なアカウントのメンバーシップエントリを持っている必要があります。アクティブな構成には、urlフィールドの値があります。

User
  has_many :memberships
  has_many :accounts, :through => :memberships
  has_many :active_accounts, :through => :memberships, 
            :source => :account, :conditions => "memberships.url IS NOT NULL"  

  accepts_nested_attributes_for :memberships
end

curent_user.active_accounts # will return the accounts with configuration
curent_user.accounts # will return all possible accounts

を追加しbefore_filterて、ユーザーが持つことができるすべてのメンバーシップを初期化します。

class UsersController

  before_filter :initialize_memberships, :only => [:new, :edit]

private

  def initialize_memberships
    accounts =  if @user.accounts.present? 
      Account.where("id NOT IN (?)", @user.account_ids) 
    else
      Account.scoped
    end        
    accounts.each do |account|
      @user.memberships.build(:account_id => account.id)
    end
  end
end    

このシナリオでは、newアクションの前にメンバーシップを初期化する必要があり、すべてのメンバーシップをcreateアクションに保存する必要があります(メンバーシップがない場合でもurl)。

編集アクションでは、追加のデータマッサージを実行する必要はありません。

ノート:

フォーム/データの管理が簡単になるため、このアプローチを提案しています。Account関連付けられているの数が少ない場合にのみ使用してください。

于 2013-03-13T21:28:52.250 に答える
2

コントローラで、特定のユーザーのメンバーシップのリストを取得します

# controller
# no need to make this an instance variable since you're using fields_for in the view
# and we're building additional memberships later
memberships = @user.memberships

次に、各アカウントをループして、ユーザーがまだアカウントのメンバーシップを持っていない場合はメンバーシップを作成します。

# still in the controller
Account.find_each do |account|
  unless memberships.detect { |m| m.account_id == account.id }
    @user.memberships.build account_id: account.id
  end
end

その後、あなたの見解では、あなたは何も変更しません:)

于 2013-03-13T23:37:53.993 に答える