0

I am having problems with the following scenario:

My users do searches by keywords which produces a list. The user has 2 actions either add them to a favorites table or block them using check boxes.

The problem I have is that when users click "Add to Favorites" the form passes a list of hashes to my strong params method and I am not able to pass it correctly.

I think the problem is that the hash required by strong_params is inside another hash.

Also I have no idea on how to pass the same hash to the BlockController when user click "Block"

This is the error message:

param is missing or the value is empty: {:favorites=>{:name=>"Jon Doe", :title=>"Provider", :company=>"Acme", :location=>"Dubai", :profile=>"Group A", :notes=>""}}

My results.html.erb is

<table class="table table-striped table-bordered">
  <tr>
      <th class="center">Name</th>
      <th class="center">Title</th>
      <th class="center">Company</th>
      <th class="center">Location</th>
      <th class="center">Profile</th>
      <th class="center">Select</th>

  </tr>
  <%= form_tag favorites_path do %>
        <%= @results.length %>
        <% @results.each do |key,value| %>

            <tr>
              <td><%= value['name'] %></td>
              <td><%= value['title'] %></td>
              <td><%= value['company'] %></td>
              <td><%= value['location'] %></td>
              <td><%= link_to 'Profile', value['profile'],:target => "_blank"%></td>
              <td><%=check_box_tag 'favorite[]',  {:name => value['name'],:title =>value['title'],:company => value['company'],:location => value['location'], :profile=> value['profile'], :notes =>""}%></td>

        </tr>

        <% end %>
    <%= submit_tag "Add to Favorites", name: 'add', class: 'btn btn-primary' %>
    <%= submit_tag "Block Profiles", name: 'block', class: 'btn btn-danger' %>
  <% end %>
</table>

this is how my strong_params method looks:

def favorite_params

  params[:profiles].each do |e|
    params.require(e).permit(:name, :title, :company, :location, :profile, :notes)
  end
end

Any ideas?

Update:

I am able to pass params as:

def favorite_params
      params.permit(:commit,favorite:[])
    end

create method:

def create
    @favorite = Favorite.new(favorite_params)
    @favorite.user_id = current_user.id
    respond_to do |format|
      if @favorite.save
        format.html { redirect_to @favorite, notice: 'Favorite was successfully created.' }
        format.json { render :show, status: :created, location: @favorite }
        format.js { render :show, status: :created, location: @favorite }

      else
        format.html { render :new }
        format.json { render json: @favorite.errors, status: :unprocessable_entity }

      end
    end
 end
1
  • Suggest you to keep your original version of view scripts, and move the new view scripts under Update section. Commented Aug 15, 2014 at 8:19

2 Answers 2

2

Reference to http://api.rubyonrails.org/classes/ActionController/Parameters.html Don't use each, use permit or require directly Try this:

params.permit(profiles: {favorites: [:name, :title, :company, :location, :profile, :notes]})
#or :
params.permit(profiles: [{favorites: [:name, :title, :company, :location, :profile, :notes]}])
#=>{:profiles=>{:favorites=>{:name=>"Jon Doe", :title=>"Provider", :company=>"Acme", :location=>"Dubai", :profile=>"Group A", :notes=>""}}}

or :

params.require(:profiles).permit( favorites: [:name, :title, :company, :location, :profile, :notes])
#=>{:favorites=>{:name=>"Jon Doe", :title=>"Provider", :company=>"Acme", :location=>"Dubai", :profile=>"Group A", :notes=>""}}

UPDATE

According to OP's modification of the view, the favorite_params should be:

params.require(:favorite)

Then in the create action use each to create every member of the array, becase check_box pass string as value, we have to eval the string into hash again.

favorite_params.each do |fp|
  f=Favorite.new(eval(fp))
  f.user_id = current_user.id
  f.save
end

But use eval to transfer the params is not safe. I suggest you to modify your view to:

<%= form_tag favorites_path do %>
  <%= @results.length %>
  <% @results.each do |key,value| %>
    <tr>
      <td><%= value['name'] %></td>
      <td><%= value['title'] %></td>
      <td><%= value['company'] %></td>
      <td><%= value['location'] %></td>
      <td><%= link_to 'Profile', value['profile'],:target => "_blank"%></td>
      <td><%= check_box_tag "favorites[#{value['name']}][checked]", 'checked',true %>
          <%= hidden_field_tag "favorites[#{value['name']}][name]" , value['name'] %>
          <%= hidden_field_tag "favorites[#{value['name']}][title]" , value['title'] %>
          <%= hidden_field_tag "favorites[#{value['name']}][company]" , value['company'] %>
          <%= hidden_field_tag "favorites[#{value['name']}][location]" , value['location'] %>
          <%= hidden_field_tag "favorites[#{value['name']}][profile]" , value['profile'] %>
          <%= hidden_field_tag "favorites[#{value['name']}][note]" , "" %>
      </td>
    </tr>
  <% end %>
  <%= submit_tag "Add to Favorites", name: 'add', class: 'btn btn-primary' %>
  <%= submit_tag "Block Profiles", name: 'block', class: 'btn btn-danger' %>
<% end %>

From this view, you may have params like this:

{:favorites=>{
  "Jon Doe" => {:checked => "checked", :name=>"Jon Doe", :title=>"Provider", :company=>"Acme", :location=>"Dubai", :profile=>"Group A", :notes=>""},
  "Alberto" => {:name=>"Alberto", :title=>"DS", :company=>"Dufrain", :location=>"chester", :profile=>"", :notes=>""}
  }
}

Then change your favorite_params to :

params.require(:favorites).select{|k,v| v[:checked]}.map{|k,v| v.except(:checked)}

Use select to get all checked members, and except the checked hash key that generated by check_box,so you could get an array of hashes like:

[{"name"=>"Jon Doe", "title"=>"Provider", "company"=>"Acme", "location"=>"Dubai", "profile"=>"Group A", "notes"=>""}]

Then you could use favorite_params safely without eval.

But on my point, your requiement is so similar as Mark V's question. So you can study using accepts_nested_attributes_for to simplify your code.

Sign up to request clarification or add additional context in comments.

5 Comments

thanks but does not work - it passes the strong_params but crashes in the def create with this error ``` {"profiles"=>[]} Unpermitted parameters: utf8, authenticity_token, add```
Can you post your create method's code. I updated my answer to show the results that strong_params returned, require and permit return differently, may cause the create method's error.
I am able to pass params using params.permit(:commit,favorite:[]) but no idea how create will process multiple records at the same time. I slighty modified the form to make easier pass data
Can you puts @favorite in your create action and see what happend?
favorite_params has the following values:{"commit"=>"Add to Favorites", "favorite"=>["{:name=>\"Alberto\", :title=>\"DS\", :company=>\"Dufrain\", :location=>\"chester\", :profile=>\"\", :notes=>\"\"}", "{:name=>\"Eduardo\", :title=>\"DS\", :company=>\"Dufrain\", :location=>\"chester\", :profile=>\"\", :notes=>\"\"}"]}
1

i am on the way home so have to use my phone to type a new answer. my spell may wrong.

as you see in your console. you should get the favorites array use require only.

params.require(:favorite)

then in your create action use each to create every member of the array.

favorite_params.each do |fp|
  f=Favorite.new(fp)
  f.user_id =
  f.save
end

2 Comments

nearly there! fp is a string to need to use eval(fp) to converted back to a hash. Could you update ur answer with the eval() so I can mark it a solution? Many thanks for ur help
This answer I posted with another temporary account on my phone, so I may delete it later. And I updated my original answer an have more advise to you. You know for some reason SO's sing in page is invald in China, I have to use different accounts at different divices. Sorry for the confusion of the two answers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.