8

RailsCast、別のネストされた属性のビデオ、多くの SO 投稿を見て、しばらくこれと格闘しましたが、まだ理解できません。それが小さなものであることを願っています。

User(Devise によって作成された) と(別名、製品のウィッシュ リスト) の2 つのモデルがあり、彼らがサインアップするときにLockerを作成しようとしています。私のログインフォームには、新しいユーザー登録時に作成されるロッカーに割り当てようとしている新しい(適切に呼ばれる) の名前のフィールドがあります。私がこれまでに迎えたのは次のとおりです。LockerUserLocker:name

WARNING: Can't mass-assign protected attributes: locker

accepts_nested_attributesとの両方のモデルのすべての組み合わせを試しましたがattr_accesible、まだ何も機能しません。Devise#create メソッドによって処理されていることをログから確認できます。また、Devise が私のモデルを思いどおりに作成できるほど賢くないこともわかっています :)

私の2つのモデルの関連部分は次のとおりです。

# user.rb    
class User < ActiveRecord::Base
  attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :locker_attributes

  # Associations
  has_many :lockers
  has_many :lockups, :through => :lockers

  # Model nesting access
  accepts_nested_attributes_for :lockers
end

# locker.rb
class Locker < ActiveRecord::Base
  belongs_to :user
  has_many :lockups
  has_many :products, :through => :lockups 

  attr_accessible :name, :description
end

# lockers_controller.rb (create)
    @locker = current_user.lockers.build(params[:locker])
    @locker.save

どうにかしてこれを機能させるには、 Devise のcreateメソッドをオーバーライドする必要があると思いますが、私はレールにまったく慣れておらず、すべてのブラック ボックスの「魔法」の性質に慣れてきています。

誰かが私を助けることができれば、私は信じられないほど感謝しています. そのままでは、すでにこれに多くの時間を費やしています:)

編集:私は自分の問題で何かを省略したことに気付きました。私のLockerモデルにはname、 、description(必須ではありません)、およびuser_idにリンクするための3 つの属性がありUserます。私のサインアップ フォームは のみを必要とするnameため、ネストされたフォームのすべての属性をループするわけではありません。それも私の問題と関係があるのでしょうか?

EDIT 2: DeviseのRegistrationsController#createメソッドをオーバーライドする方法もわかりましたが、そこに何を置くべきかわかりません。Devise の全体像resourceは私には理解できません。また、Devise のソース コードを参照してRegistrationsControllerもあまり役に立ちませんでした。

ボーナス ポイント:ユーザーが無効なデータを含むログイン フォームを送信すると、Lockerフィールドは常に空白に戻りますが、Devise の通常のフィールドであるユーザー名と電子メールには入力されます。これも簡単に修正できますか? もしそうなら、どのように?

4

2 に答える 2

2

誰かが、より「Rails 4'y」な方法でソリューションを見つけ出すのを手伝ってくれました.Devisestrong attributesをオーバーライドする方法sign_up_params(サインアップフォームからのすべてのデータをキャッチするため)。

  def sign_up_params
    params.require(:user).permit(:username, :email, :password, :lockers_attributes)
 end

Gemfile の追加:gem 'strong_parameters'

明らかに強力なパラメーターにより宣言が不要になるためattr_accessible、ファイル内のステートメントをコメントアウトします。user.rbattr_accessible

 # attr_accessible :username, :email, :password, :password_confirmation, :lockers

そして、フォームを送信する前にロッカーを構築する正しい方法: ネストされたフォームの先頭:

<%= l.input :name, :required => true, label: "Locker name", :placeholder => "Name your first locker" %>

あなたのご親切に感謝します。コードベース全体を見ないと、このような質問に答えるのが難しいことはわかっています。

于 2013-05-26T16:22:02.623 に答える
2

まず、タイプミスがあります:

attr_accessible :locker_attributes

複数形である必要があります:

attr_accessible :lockers_attributes

次に、使用する標準的な方法nested_attributesは次のとおりです。

<%= form_for @user do |f| %>
  <%# fields_for will iterate over all user.lockers and 
      build fields for each one of them using the block below,
      with html name attributes like user[lockers_attributes][0][name].
      it will also generate a hidden field user[lockers_attributes][0][id]
      if the locker is already persisted, which allows nested_attributes
      to know if the locker already exists of if it must create a new one
  %>
  <% f.fields_for :lockers do |locker_fields| %>
    <%= locker_fields.label      :name %>
    <%= locker_fields.text_field :name %>
  <% end %>
<% end %>

そしてあなたのコントローラーで:

def new
  @user = User.new
  @user.lockers.build
end

def create
  # no need to use build here : params[:user] contains a
  # :lockers_attributes key, which has an array of lockers attributes as value ;
  # it gets assigned to the user using user.lockers_attributes=, 
  # a method created by nested_attributes
  @user = User.new( params[:user] )
end

補足として、コントローラーで新しいユーザー用の新しいロッカーをさまざまな方法で構築することを回避できます。

  • でファクトリ メソッドを作成するUserか、オーバーライドnewするか、コールバックを使用して、after_initializeインスタンス化されたすべての新しいユーザーがロッカーを自動的に作成するようにします。

  • 特定のオブジェクトを に渡しますfields_for:

    <% f.fields_for :lockers, f.object.lockers.new do |new_locker_fields| %>
    
于 2013-05-25T09:07:17.273 に答える