3

我在这里阅读了许多其他主题(123 ...),但没有一个能真正解决我的问题。

这是我的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

如您所见,我的加入模型Membership有一个附加属性::url.

在我的Accounts表中,我存储了在线服务的名称,例如 GitHub、Stack Overflow、Twitter、Facebook、LinkedIn。我总共有9个。这是一个固定数量的帐户,我不会经常更新。

在我的用户表单中,我想创建这个:

用户嵌套表单

在这些字段中输入的值应仅在成员资格表中提交,使用 3 个值:

  • 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 %>

我想要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 %>

我正在尝试在 Memberships 表的每一列中手动输入 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 %>

我正在我的用户表单中为我的会员模型创建一个嵌套表单。

几乎完美地工作:

  • 正好 9 个字段,每个帐户一个
  • 没有重复

但是,它只有在我的 Memberships 表已经被填充时才有效!(例如使用选项#2)。

所以我尝试使用 UsersController 构建一些实例:

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

但是我的 m.label m.object.account.name 行仍然出现此错误。

undefined method `name' for nil:NilClass

无论如何,我可能在这里通过模型遗漏了一些关于 has_many 的内容。我已经设法创建了 has_and_belongs_to_many 关联,但在这里,我想通过第一个模型(用户)使用关于第三个模型(帐户)的信息来处理该连接模型(会员)。

我会很感激你的帮助。谢谢你。

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 回答