Rails 4 - 关联 - 嵌套属性 - 不允许的参数

Rails 4 - Associations - nested attributes - unpermitted parameter

我正在尝试在 Rails 4 中制作一个应用程序。我很难建立基本关系。

我有用户、个人资料、愿景、个性和资格的模型。

协会是:

User.rb

Profile.rb

belongs_to :user


  has_one :personality
    accepts_nested_attributes_for :personality

  has_many :qualifications  
    accepts_nested_attributes_for :qualifications,  reject_if: :all_blank, allow_destroy: true

  has_one :vision
    accepts_nested_attributes_for :vision, reject_if: :all_blank, allow_destroy: true    

Vision.rb

belongs_to :profile

Personality.rb

  belongs_to :profile

Qualifications.rb

belongs_to :profile

控制器是:

用户

class UsersController < ApplicationController
before_action :set_user, only: [:index, :show, :edit, :update, :finish_signup, :destroy]

  def index
    # if params[:approved] == "false"
    #   @users = User.find_all_by_approved(false)
    # else
      @users = User.all
    # end

  end

  # GET /users/:id.:format
  def show
    # authorize! :read, @user
  end

  # GET /users/:id/edit
  def edit
    # authorize! :update, @user
  end

  # PATCH/PUT /users/:id.:format
  def update
    # authorize! :update, @user
    respond_to do |format|
      if @user.update(user_params)
        sign_in(@user == current_user ? @user : current_user, :bypass => true)
        format.html { redirect_to @user, notice: 'Your profile was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # GET/PATCH /users/:id/finish_signup
  def finish_signup
    # authorize! :update, @user 
    if request.patch? && params[:user] #&& params[:user][:email]
      if @user.update(user_params)
        @user.skip_reconfirmation!
        sign_in(@user, :bypass => true)
        redirect_to root_path, notice: 'Your profile was successfully updated.'
        # redirect_to [@user, @user.profile || @user.build_profile]
        # sign_in_and_redirect(@user, :bypass => true)
      else
        @show_errors = true
      end
    end
  end

  # DELETE /users/:id.:format
  def destroy
    # authorize! :delete, @user
    @user.destroy
    respond_to do |format|
      format.html { redirect_to root_url }
      format.json { head :no_content }
    end
  end

  private
    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      # params.require(:user).permit(policy(@user).permitted_attributes)
      accessible = [ :first_name, :last_name, :email, :avatar ] # extend with your own params
      accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank?
      # accessible << [:approved] if user.admin
      params.require(:user).permit(accessible)
    end

end

简介

class ProfilesController < ApplicationController
  before_action :set_profile, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!
  after_action :verify_authorized

  # GET /profiles
  # GET /profiles.json
  def index
    @profiles = Profile.all
    authorize @profiles
  end

  # GET /profiles/1
  # GET /profiles/1.json
  def show
  end

  # GET /profiles/new
  def new
    @profile = Profile.new
    @profile.qualifications.build
    @profile.build.vision
    @profile.build.personality
    @profile.addresses.build

    authorize @profile

  end

  # GET /profiles/1/edit
  def edit
  end

  # POST /profiles
  # POST /profiles.json
  def create
    @profile = Profile.new(profile_params)
    authorize @profile

    respond_to do |format|
      if @profile.save
        format.html { redirect_to @profile }
        format.json { render :show, status: :created, location: @profile }
      else
        format.html { render :new }
        format.json { render json: @profile.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /profiles/1
  # PATCH/PUT /profiles/1.json
  def update

    # successful = @profile.update(profile_params)

    # Rails.logger.info "xxxxxxxxxxxxx"
    # Rails.logger.info successful.inspect
    # user=@profile.user
    # user.update.avatar
    respond_to do |format|
      if @profile.update(profile_params)
        format.html { redirect_to @profile }
        format.json { render :show, status: :ok, location: @profile }
      else
        format.html { render :edit }
        format.json { render json: @profile.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /profiles/1
  # DELETE /profiles/1.json
  def destroy
    @profile.destroy
    respond_to do |format|
      format.html { redirect_to profiles_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_profile
      @profile = Profile.find(params[:id])
      authorize @profile
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def profile_params
     params.require(:profile).permit(:user_id, :title, :hero, :overview, :research_interest, :occupation, :external_profile, 
        :working_languages, :tag_list,
          user_attributes: [:avatar],
          personality_attributes: [:average_day, :fantasy_project, :preferred_style],
          vision_attributes: [:id, :profile_id, :long_term, :immediate_challenge], 
          qualifications_attributes: [:id, :level, :title, :year_earned, :pending, :institution, :_destroy],
          addresses_attributes: [:id, :unit, :building, :street_number, :street, :city, :region, :zip, :country, :latitude, :longitude, :_destroy],
          industries_attributes: [:id, :sector, :icon] )
    end
end

愿景

class VisionsController < ApplicationController
  before_action :set_vision, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /visions
  # GET /visions.json
  def index
    @visions = Vision.all
    authorize @visions
  end

  # GET /visions/1
  # GET /visions/1.json
  def show
  end

  # GET /visions/new
  def new
    @vision = Vision.new
    authorize @vision
  end

  # GET /visions/1/edit
  def edit
  end

  # POST /visions
  # POST /visions.json
  def create
    @vision = Vision.new(vision_params)
    authorize @vision

    respond_to do |format|
      if @vision.save
        format.html { redirect_to @vision }
        format.json { render :show, status: :created, location: @vision }
      else
        format.html { render :new }
        format.json { render json: @vision.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /visions/1
  # PATCH/PUT /visions/1.json
  def update
    respond_to do |format|
      if @vision.update(vision_params)
        format.html { redirect_to @vision }
        format.json { render :show, status: :ok, location: @vision }
      else
        format.html { render :edit }
        format.json { render json: @vision.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /visions/1
  # DELETE /visions/1.json
  def destroy
    @vision.destroy
    respond_to do |format|
      format.html { redirect_to visions_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_vision
      @vision = Vision.find(params[:id])
      authorize @vision
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def vision_params
      params[:vision].permit(:profile_id, :long_term, :immediate_challenge)
    end
end

资格

class QualificationsController < ApplicationController
  before_action :set_qualification, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /qualifications
  # GET /qualifications.json
  def index
    @qualifications = Qualification.all
    authorize @qualifications
  end

  # GET /qualifications/1
  # GET /qualifications/1.json
  def show
  end

  # GET /qualifications/new
  def new
    @qualification = Qualification.new
    authorize @qualification
  end

  # GET /qualifications/1/edit
  def edit
  end

  # POST /qualifications
  # POST /qualifications.json
  def create
    @qualification = Qualification.new(qualification_params)
    authorize @qualification

    respond_to do |format|
      if @qualification.save
        format.html { redirect_to @qualification }
        format.json { render :show, status: :created, location: @qualification }
      else
        format.html { render :new }
        format.json { render json: @qualification.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /qualifications/1
  # PATCH/PUT /qualifications/1.json
  def update
    respond_to do |format|
      if @qualification.update(qualification_params)
        format.html { redirect_to @qualification }
        format.json { render :show, status: :ok, location: @qualification }
      else
        format.html { render :edit }
        format.json { render json: @qualification.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /qualifications/1
  # DELETE /qualifications/1.json
  def destroy
    @qualification.destroy
    respond_to do |format|
      format.html { redirect_to qualifications_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_qualification
      @qualification = Qualification.find(params[:id])
      authorize @qualification
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def qualification_params
      params[:qualification].permit(:profile_id, :level, :title, :year_earned, :pending, :institution)
    end
end

个性

class PersonalitiesController < ApplicationController
  before_action :set_personality, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /personalities
  # GET /personalities.json
  def index
    @personalities = Personality.all
    authorize @personalities
  end

  # GET /personalities/1
  # GET /personalities/1.json
  def show
  end

  # GET /personalities/new
  def new
    @personality = Personality.new
    authorize @personality
  end

  # GET /personalities/1/edit
  def edit
  end

  # POST /personalities
  # POST /personalities.json
  def create
    @personality = Personality.new(personality_params)
    authorize @personality

    respond_to do |format|
      if @personality.save
        format.html { redirect_to @personality }
        format.json { render :show, status: :created, location: @personality }
      else
        format.html { render :new }
        format.json { render json: @personality.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /personalities/1
  # PATCH/PUT /personalities/1.json
  def update
    respond_to do |format|
      if @personality.update(personality_params)
        format.html { redirect_to @personality }
        format.json { render :show, status: :ok, location: @personality }
      else
        format.html { render :edit }
        format.json { render json: @personality.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /personalities/1
  # DELETE /personalities/1.json
  def destroy
    @personality.destroy
    respond_to do |format|
      format.html { redirect_to personalities_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_personality
      @personality = Personality.find(params[:id])
      authorize @personality
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def personality_params
      params[:personality].permit( :average_day, :fantasy_project, :preferred_style)
    end
end

个人资料表格有:

<div class="container-fluid"> 
  <div class="row">
    <div class="col-xs-10 col-xs-offset-1" >

    <%= simple_form_for(@profile, multipart: true) do |f| %>
            <%= f.error_notification %>

              <div class="form-inputs">

          <div class="intpol2">
            About you
          </div>

          <div class="row">
            <div class="col-md-4">
              <%= f.input :title,  autofocus: true %>
            </div>

            <div class="col-md-8">
              <%= f.input :occupation, :label => "Your occupation or job title" %>
            </div>

          </div>

          <div class="row">
            <div class="col-md-6">
               <%= render 'users/profileimgform', f: f %>   
            </div>

            <div class="col-md-6">
             <%= f.input :hero, as: :file, :label => "Add a background image to your profile page" %>
            </div>

          </div>

          <div class="row">
            <div class="col-md-6">
               <%= f.input :working_languages, :label => "Select your working languages" %>
            </div>

            <div class="col-md-6">
             <%= f.input :external_profile, :label => "Add a link to your external profile"  %>
            </div>

          </div>

          <div class="row">
            <div class="col-md-12">
              <%= f.input :overview, :label => "Tell us about yourself", :input_html => {:rows => 10} %>
            </div>
          </div>

          <div class="row">
            <div class="col-md-12">


              <%= render 'industries/industry_selector', f: f %>  
            </div>
          </div>

          <div class="row">

            <div class="intpol2">
              Your professional qualifications
            </div>
            <%= f.simple_fields_for :qualifications do |f| %>

              <%= render 'qualifications/qualification_fields', f: f %>  
            <% end %>
          </div>


          <div class="row">

            <div class="col-md-6">

               <%= link_to_add_association 'Add a qualification', f, :qualifications, partial: 'qualifications/qualification_fields' %>

            </div>

          </div>

          <div class="row">

            <div class="intpol2">
              Your career
            </div>

              <%= render 'personalities/form', f: f %>
          </div>

          <div class="row">

            <div class="intpol2">
              Your research vision
            </div>

          </div>

          <div class="row">

            <div class="intpol2">

              Your addresss
            </div>

              <%= f.simple_fields_for :addresses do |f| %>

              <%= render 'addresses/address_fields', f: f %>  
              <% end %>
          </div>

          <div class="row">
            <div class="col-md-6">

               <%= link_to_add_association 'Add an address', f, :addresses, partial: 'addresses/address_fields' %>

            </div>

                </div>

              <div class="form-actions">
                <%= f.button :submit, "Submit", :class => 'formsubmit' %>
              </div>

        <% end %>
         </div>
    </div>  
  </div>
</div>      

嵌套形式为:

愿景

 <div class="form-inputs">
    <%= f.input :long_term, as: :text, :label => "What is your long term research vision?", :input_html => {:rows => 10} %>

    <%= f.input :immediate_challenge, as: :text, :label => "What do you see as the immediate challenge to be addressed in pursuit of your long-term vision?",  :input_html => {:rows => 10} %>

  </div>

资格

<div class="nested-fields">
<div class="container-fluid">



          <div class="form-inputs">


            <div class="row">
                <div class="col-md-6">
                    <%= f.input :title, :label => "Your award" %> 
                </div>

                <div class="col-md-6">


                </div>


            </div>

            <div class="row">
                <div class="col-md-8">
                    <%= f.input :pending, :label => "Are you currently studying toward this qualification?" %>
                </div>
            </div>       

            <div class="row">
                <div class="col-md-4">
                    <%= f.input :level,   collection: [ "Bachelor's degree", "Master's degree", "Ph.D", "Post Doctoral award"] %>
                </div>




                <div class="col-md-4">
                <%= f.input :year_earned, :label => "When did you graduate?", collection: (Date.today.year - 50)..(Date.today.year) %>
                </div>

          </div>


          <div class="row">
                <div class="col-md-6">
                    <%= link_to_remove_association 'Remove this qualification', f %>
                </div>

          </div>


          </div>

</div>  
</div>      

个性

<%= f.simple_fields_for :profile do |f| %>
      <%= f.simple_fields_for :personality do |ff| %>

  <div class="form-inputs">
      <%= ff.input :average_day, :label => "What does your day to day work life involve?", as: :text, :input_html => {:rows => 5}  %>
      <%= ff.input :fantasy_project, :label => "Describe your fantasy project", as: :text, :input_html => {:rows => 5}  %>
      <%= ff.input :preferred_style, :label => "How do you like to work (distributed teams, on site, easy going about it)?", as: :text, :input_html => {:rows => 5}  %>


  </div>

  <% end %>

<% end %>

个人资料显示页面有:

<div class="intpol3">
                <%= @profile.personality.try(:average_day) %>
            </div>

            <div class="profilesubhead">
                My fantasy league research project
            </div>
            <div class="intpol3">
                <%= @profile.personality.try(:fantasy_project) %>
            </div>

            <div class="profilesubhead">
                Working style
            </div>
            <div class="intpol3">
                <%= @profile.personality.try(:preferred_style) %>
            </div>

            <div class="profilesubhead">
                My research vision
            </div>
            <div class="profilesubhead">
                <%= @profile.vision.try(:long_term) %>
            </div>

            <div class="profilesubhead">
                Immediate research challenge in my field
            </div>
            <div class="profilesubhead">
                <%= @profile.vision.try(:immediate_challenge) %>
            </div>

路线是:

resources :profiles, only: [:show, :edit, :update, :destroy]

  resources :qualifications
  resources :personalities
  resources :visions
  resources :users do
     resources :profiles, only: [:new, :create]
  end

从上面可以看出,我尝试了多种不同的解决方案,包括使用 cocoon gem(我已将其用于资格模型)。

没有任何效果。配置文件显示页面上显示的唯一属性是存储在配置文件 table 或用户 table 中的属性。 None 个属于个人资料的模型正在个人资料显示中显示。正在显示与配置文件具有多态关联的模型。

目前,当我保存并尝试此操作时,本地主机服务器显示一个名为 'Unpermitted parameter: profile' 的错误。我可以看到资格,表单中的条目显示在服务器中,但它们没有出现在个人资料页面上。对于其余每个嵌套属性 - none 显示在配置文件显示页面上。 rails 控制台显示个性的所有属性(显示个人资料页面的用户的个人资料 ID 为零)。

在我的配置文件表单中,我什至无法显示远景表单字段。我认为这可能是因为我添加了这个:

reject_if: :all_blank, allow_destroy: true 

在我的配置文件模型中接受 :vision 的嵌套属性 - 但评论该部分并不能改善情况。

我之前问过这个问题,但找不到任何帮助。

Rails - Displaying associated attributes - unpermitted parameters

我已经尝试了我在 post 中列出的每个解决方案(我认为我在 post 末尾附上的站点点文章是我所拥有的最接近相关的内容能够找到)。

我想不出要检查或更改的东西。谁能看出我做错了什么?

当我尝试通过向配置文件表单的个性部分添加条目来更新配置文件时,服务器显示以下输出:

Started PATCH "/profiles/8" for ::1 at 2016-01-09 12:38:04 +1100
Processing by ProfilesController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xul2nPMbg/3MnMPoTMtEIFfVg==", "profile"=>{"title"=>"", "occupation"=>"tester", "working_languages"=>"tester", "external_profile"=>"tester", "overview"=>"tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester tester ", "qualifications_attributes"=>{"0"=>{"title"=>"dfds", "pending"=>"0", "level"=>"Master's degree", "year_earned"=>"1967", "_destroy"=>"false", "id"=>"4"}}, "profile"=>{"personality"=>{"average_day"=>"sdf", "fantasy_project"=>"", "preferred_style"=>""}}}, "industry"=>{"sector"=>"5"}, "commit"=>"Submit", "id"=>"8"}
  Profile Load (0.3ms)  SELECT  "profiles".* FROM "profiles" WHERE "profiles"."id" =  LIMIT 1  [["id", 8]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" =   ORDER BY "users"."id" ASC LIMIT 1  [["id", 9]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" =  LIMIT 1  [["id", 9]]
Unpermitted parameter: profile
   (0.1ms)  BEGIN
  Qualification Load (0.3ms)  SELECT "qualifications".* FROM "qualifications" WHERE "qualifications"."profile_id" =  AND "qualifications"."id" = 4  [["profile_id", 8]]
   (0.1ms)  COMMIT
Redirected to http://localhost:3000/profiles/8
Completed 302 Found in 12ms (ActiveRecord: 1.3ms)

采纳 MIHAILS 的建议

我将个性表单字段替换为:

      <%= f.simple_fields_for :personality do |ff| %>

  <div class="form-inputs">
      <%= ff.input :average_day, :label => "What does your day to day work life involve?", as: :text, :input_html => {:rows => 5}  %>
      <%= ff.input :fantasy_project, :label => "Describe your fantasy project", as: :text, :input_html => {:rows => 5}  %>
      <%= ff.input :preferred_style, :label => "How do you like to work (distributed teams, on site, easy going about it)?", as: :text, :input_html => {:rows => 5}  %>


  </div>

  <% end %>

当我尝试这个时,个性表单字段根本不会呈现为配置文件表单的一部分

听取下一个建议

我将配置文件控制器中的构建个性操作替换为:

@profile.personality = Personality.new

之前是:@profile.build.personality

当我尝试此操作时,我遇到了与以前相同的错误 - 我根本看不到个性的表单字段。

采纳 TRH 的建议:

如果我进行新操作:

@profile.build_personality 

我仍然看不到个性字段的表单。之前的尝试没有变化

进一步更新

看来Mihail的第二个建议中的解释与TRH的建议是一样的效果。目前,我的配置文件控制器有这个新动作:

 def new
    @profile = Profile.new
    @profile.qualifications_build
    @profile.build_vision
    @profile.build_personality 
    @profile.addresses_build

    authorize @profile

  end

还是不行。

采纳 MIHAIL 的下一步建议

def new
    @profile = Profile.new
    @profile.qualifications_build
    @profile.build_vision
    @profile.build_personality unless personality
    @profile.addresses_build

    authorize @profile

  end

我仍然看不到个性的个人资料表单字段。

解决方案:

def new
    @profile = Profile.new
    @profile.qualifications_build
    @profile.build_vision
    @profile.build_personality unless @profile.personality
    @profile.addresses_build

    authorize @profile

  end

  # GET /profiles/1/edit
  def edit
    @profile.build_personality unless @profile.personality
  end

问题出在个性字段部分。如果您仔细查看更新时提交给服务器的属性,您会发现它们是错误的。

"profile"=>{"profile"=>{"personality"=>{"average_day"=>"sdf"}}

因此,要解决此问题,您需要检查此部分并仅在其中保留嵌套字段块。

<%= f.simple_fields_for :personality do |ff| %>

  <div class="form-inputs">
    <%= ff.input :average_day, :label => "What does your day to day work life involve?", as: :text, :input_html => {:rows => 5}  %>
    <%= ff.input :fantasy_project, :label => "Describe your fantasy project", as: :text, :input_html => {:rows => 5}  %>
    <%= ff.input :preferred_style, :label => "How do you like to work (distributed teams, on site, easy going about it)?", as: :text, :input_html => {:rows => 5}  %>
  </div>

<% end %>