Pass a local value to a controller method in Rails 4 - html

I have the following code which displays a dropdown menu (I have it this way the so the form shows the last selected option). I would like to pass the value associated with the selection to a method in my controller.
I want to save this to the the value of "choice" which is specified as an integer in my user model. The initial value of choice is 0.
I can't seem to find a way to do this with the local "value".
<select class="form-control">
<option value= 1>One</option>
<option value= 2>Two</option>
<option value= 3>Three</option>
</select>
<%= link_to "Select", {controller: :controller_name, action: :method_name, value: :value} %>
Controller method (I am using Devise to call "current_user")
def method_name
current_user.choice = value
current_user.save
redirect_to root_path
end

Try a form, here is an example of what you need below:
<%= form_tag(url_for(controller: 'controller_name', action: 'method_name'), method: :method_type(PUT, POST, etc.) do %>
<div class="form-group">
<%= label_tag(:choice, "Choice") %>
<%= select_tag(:choice, options_for_select([0, 1, 2, 3], selected: 0)) %>
</div>
<%= submit_tag 'Save'%>
<% end %>
As a commenter eluded to, in your method you can then use:
def method_name
current_user.choice = params[:choice]
current_user.save
redirect_to root_path
end

Related

How to make the submit button call a function?

<%= form_tag('add_person', method: 'get') do %>
<%= label_tag(:name, 'Name') %>
<%= text_field_tag(:name) %>
<%= submit_tag 'Add new person' %>
<% end %>
<%= def add_person
if params[:name] == "John")
enter code here
else
enter code here
end
end %>
How do I make the submit button call the function add_person? I'm using Ruby/Rails
Calling one or more methods via submit button:
The form_tag helper determines the controller method to be called:
<%= form_tag('controller/controller_method', method: 'put') do %>
The submit_tag passes a value to the controller where it's evaluated.
<%= submit_tag "Add Person" %>
In the controller, you branch based on the value passed by your submit button:
def controller_method
if params[:commit] == "Add Person"
add_person
elsif params[:commit] == "Method 2"
method_2
elsif params[:commit] == "Method 3"
method_3
end
end
Calling method via arbitrary button
You probably have something like this at the bottom of your form:
<div class="actions">
<%= f.submit %>
</div>
which can be replaced with the button_to helper, like so:
<%= button_to "Submit", :method=> 'add_person' %>
Your add_person method would have to be defined in the controller for the object to which your form refers.

Issue with Nested Form rendering

I have a rails 4 app that has a form that looks like:
<%= form_for #store, :html => {:multipart => true} do |f| %>
<%= f.fields_for :products do |product| %>
<%= render partial: "edit_product_fields", locals: {product:product} %>
<% end %>
<%= f.submit %>
<% end %>
and the edit_product_fields partial looks like:
<select>
<option value="Textbook" <% if product.type_of == "Textbook" %>selected<% end %>>Textbook</option>
<option value="Magazine" <% if product.type_of == "Magazine" %>selected<% end %>>Magazine</option>
<option value="Book" <% if product.type_of == "Book" %>selected<% end %>>Book</option>
</select>
When I have the code like this, I get the error:
undefined method `type_of' for #<NestedForm::Builder:0x00000102304f78>
but if I change the render line to (I just made it less explicit by taking out partial:):
<%= render "edit_product_fields", locals: {product:product} %>
I get the error:
undefined local variable or method `product' for #<#<Class:0x0000010235a248>:0x0000010684b3c0>
In your first code block, you have a Builder object being stored as product.
Fortunately, Builder provides an object method so you can access the actual object that it's representing in the form:
<select>
<option value="Textbook" <%= 'selected' if product.object.type_of == "Textbook" %>>Textbook</option>
<option value="Magazine" <%= 'selected' if product.object.type_of == "Magazine" %>>Magazine</option>
<option value="Book" <%= 'selected' if product.object.type_of == "Book" %>>Book</option>
</select>
Well type_of is not a ruby method. It looks like it's an attempt to type check though... But type checking is generally frowned upon in duck-typed languages. At any rate, we can take advantage of a Rails Form Helper instead and make this code a one-liner. But first...
The reason the render is complaining about undefined local variable or methodproduct'` after your change is because the render call expects either the first argument to be a partial name and the second to be a hash of locals:
<%= render "partial_name", local1: "a", local2: "b" %>
... or it expects the the whole thing to be a hash:
<%= render partial: "partial_name", locals: { local1: "a", local2: "b" } %>
Now, back to the form helper.
What you're looking for here is the select helper. This makes the following possible:
<%= product.select :type_of, %w[Textbook Magazine Book] %>
And this will render all of the same html as you've put into your _edit_product_field.html.erb partial. So you should probably just get rid of the partial to save on rendering time and put this directly into your form.
One other, minor point. It may be less confusing to call the fields_for block variable product_form instead of product. This is to help keep in mind that this is not a Product object you're dealing with, but rather a Form Generator object. Also, you don't need to specify :multipart => true in Rails 4 forms -- Rails knows to make the form multi-part if you have a file upload element within the form body.
So putting it all together:
<%= form_for #store do |f| %>
<%= f.fields_for :products do |product_form| %>
<%= product_form.select :product, %w[Textbook Magazine Book] %>
<% end %>
<%= f.submit %>
<% end %>

how to pass the value selected from a drop down list to a ruby on rails model

i am making a small website and i have a model called member and in it there a field called district
field :district, type: String
in the view of the member there is a drop down list where i can choose the district i live in
<select name="district">
<option value=" " disabled selected>(please select a district)</option>
<optgroup label="cairo">
<option>Abdeen</option>
<option>Ain Shams</option>
</optgroup>
</select>
and everthing is working good but the problem is that i want to take the value which the user select from the drop down list and save it in the model field district
you need to use form_for and write code in rails way
here is example:
<%= form_for #new_todo do |f| %>
<%= f.select :todo_item, #array_of_string_here %>
<%= f.submit "Add todo", class: "btn btn-primary" %>
<%end%>
I recommend you to create a model for district as well. And make member model belong to district model. And use "collection_select" in form_for. The code will look like..
<%= form_for #member do |f| %>
<div class="form-group">
<%= f.label :district %>
<%= f.collection_select(:district_id, #districts, :id, :districst_name, {:prompt=>false}) %>
</div>
<%= f.submit "Save", class: 'btn btn-success' %>
<% end %>
For more detail, see this link.

ERB Radio Button causing string error

I'm working with forms using Embedded Ruby and Rails 4 to create and edit Users. Each User has to be assigned a Role on creation. Initially the form was using check boxes for this and was working fine. Upon changing over to radio buttons however, I get an error.
This is the form:
<%= simple_form_for(#user, html: {class: 'form-horizontal'}) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name, autofocus: true %>
<%= f.input :email %>
<%= f.input :phone_number %>
<%= f.input :institution_pid, collection: institutions_for_select, as: :select, label: "Institution" %>
<%= f.association :roles, collection: roles_for_select, as: :radio_buttons %>
<%= f.input :password %>
<%= f.input :password_confirmation %>
</div>
<br>
<div class="form-actions">
<%= button_tag(type: 'submit', class: "btn doc-action-btn btn-success") do %>
<i class="glyphicon glyphicon-check"></i> Submit
<% end %>
<%= link_to #user, {class: "btn doc-action-btn btn-cancel"} do %>
<i class="glyphicon glyphicon-remove"></i> Cancel
<% end %>
</div>
I'm specifically asking about the f.association bit. Before, when I was using
as: :check_boxes
it worked exactly as it was supposed to. Now I get this error message:
NoMethodError in UsersController#update
undefined method `reject' for "77":String
I should note that "77" is the value of one of the radio button options.
The method throwing the error is this:
def build_role_ids
[].tap do |role_ids|
roles = Role.find(params[:user][:role_ids].reject &:blank?)
roles.each do |role|
authorize!(:add_user, role)
role_ids << role.id
end
end
end
The HTML when using radio buttons looks like this:
<label class="radio">
<input class="radio_buttons optional" id="user_role_ids_77" name="user[role_ids]" type="radio" value="77">
"Institutional Admin"
</label>
When using check boxes:
<label class="checkbox">
<input class="check_boxes optional" id="user_role_ids_77" name="user[role_ids][]" type="checkbox" value="77">
"Institutional Admin"
</label>
If I'm missing something or you need more information, please let me know. Thank you!
With checkboxes, user can select multiple values so you got an Array of role_ids returned in params[:user][:role_ids]. reject method is implemented for Arrays. Hence, it worked in that case.
With radio buttons, only one value would be selected at a time, so you'll get a String value for role_ids in params[:user][:role_ids]. reject method is not implemented for Strings. Hence, the error.
Instead of
params[:user][:role_ids].reject &:blank?
you can check if role_ids is empty or not, as it is a String object.
params[:user][:role_ids].empty?
and update build_role_ids method keeping in mind that role_ids is a String object and not an Array.
This error seems to indicate that params[:user][:role_ids] is not an Array but a single String value. This would make sense since you are changing from checkboxes (multiple values can be selected at a time = Array) to radio buttons (only a single value can be selected at a time = String).
If you truly want to change from checkboxes to radio buttons, then you'll need to update your build_role_ids method logic to expect a single value instead of an array of values.

rails helper for select_tag?

I don't get the point how can I do that code with an select helper?
<select name="cube_name">
<% #cube_names.each do |cube| %>
<option value="<%= cube %>" <% if #cube_name == cube %> selected="selected"<% end %>><%= cube %></option>
<% end %>
</select>
I have a list (#cube_names) and want a HTML select box width all values of the list and the default value (param #cube_name) should be selected.
thanks.
The select_tag helper will not auto-set the selected attribute on an item you pass. It just builds the tag. Use something like:
<%= select_tag("id_of_my_tag", #cube_names.map { |cn| "<option#{cn == cube ? " selected='selected'" : ""}>#{cn}</option>" }.join("")) %>
The first parameter is the id of the select tag, the second is a list of options (here built by mapping the cube names to strings, then joining the array into a single string).
You could alternatively use the options_for_select to build the string:
<%= select_tag("id_of_my_tag", options_for_select(#cube_names, cube)) %>