Pass a variable from view to controller from form submit - ruby-on-rails

I am trying to access a variable sent through a submit form. However it does not appear to be present once the form is submitted.
see the hidden field on line: 2
<%= form_for #import, html: { multipart: true } do |f| %>
<%= f.hidden_field :tree_id, :value => #tree.id %>
<%= f.label :new_branch_data %>
<div class="help-text">Locate a file for import. (.xls, .xlsx file type)</div>
<%= f.file_field :attachment %>
<%= f.submit "Import", class: "btn btn-primary" %>
<% end %>
After hitting submit the action called in my controller:
def index
#tree = Tree.find(params[:tree_id])
...
...
end
Hangs up on #tree = Tree.find(params[:tree_id]) and returns a
"ActiveRecord::RecordNotFound"
at /imports
Couldn't find Tree without an ID
How can I correct this so that the #tree variable referenced in the form can be passed to the controller?

You can inspect the params that you're getting but I guess you have tree_id on params[:import] so ...
def index
#tree = Tree.find(params[:import][:tree_id])
...
...
end

I realized I wasn't calling the index action directly.
When looking at my controller I was actually calling the create action which was later redirecting to the index.
def create
#import = Import.new(import_params)
if #import.save
redirect_to imports_path, notice: "Data imported successfully."
else
render "new"
end
end
I changed the redirect to pass the param,
redirect_to imports_path(tree_id: params[:import][:tree_id]), notice: "Data imported successfully."
and then accessed the passed param in the index view by adding
#tree = Tree.find(params[:tree_id])
to the top of my index action.

Related

Redirecting to "show" view of a model object when searched by attributes (NOT id)

I have a form where users look for a particular bill by some attributes of that bill, namely the "Congress Number", "Bill Type", and "Bill Number", as in 114-H.R.-67 . I want to "show" the appropriate bill, but to do that I have get the appropriate bill model in a separate action which I've called "find_by_attributes". Inside this action I perform:
#bill = Bill.find_by( params ).first
which correctly acquires the appropriate bill's id.
Now I simply want to redirect to the "show" method of this bill, as in the url
".../bills/[#bill.id]"
As of right now, at the end of my "find_by_attributes" action I do
redirect_to bills_path(#bill)
which correctly loads the show.html.erb with #bill, but does not change the url (the url is still shows the "find_by_attributes" action followed by a long query-string, instead of the clean "/bills/[:bill_id]".
How can I restructure my code to achieve the neat redirect that I desire?
Full code below:
THE FORM
<%= form_tag("bills/find_or_create", :method => :get ) do |f| %>
<%# render 'shared/error_messages', object: f.object %>
<%= fields_for :bill do |ff| %>
<%= ff.label :congress, 'Congress (i.e. 114)' %>
<%= ff.number_field :congress, class: 'form-control' %>
<%= ff.select :bill_type, options_for_select(
[['House of Representatives', 'hr'],
['Senate', 's'],
['House Joint Resolution', 'hjres'],
['Senate Joint Resolution', 'sjres'],
['House Concurrent Resolution', 'hconres'],
['Senate Concurrent Resolution', 'sconres'],
['House Resolution', 'hres'],
['Senate Resolution', 'sres']]
)
%>
<%= ff.label :bill_number, 'Bill number (i.e. 67)' %>
<%= ff.number_field :bill_number, class: 'form-control' %>
<% end %>
<%= submit_tag "Submit", class: "btn btn-primary" %>
<% end %>
THE CONTROLLER ACTIONS
def find_by_attributes
#bill = Bill.where(bill_params).first_or_create(bill_attributes)
redirect_to bills_path(#bill)
end
def show
puts bill_params
if params[:bill]
#bill = Bill.where(bill_params).first_or_create do |bill|
bill.attributes = bill_attributes
end
else
#bill = Bill.find(params[:id])
end
#subjects = Subject.where("bill_id = ?", #bill[:id])
#bill_comments = Comment.where("target = ?", #bill[:id])
end
ROUTES FILE
...
resources :bills do
get :find_by_attributes
end
...
EDIT
I make use of the turbolinks gem in my rails application.
the thing I see here is that you are calling to
redirect_to bills_path(#bill)
that in theory is not the show path, you just need to remove the "s"
redirect_to bill_path(#bill)
and as a side comment, in this line, you don't need the first part, because find_b, finds the first record matching the specified conditions, you can remove that part.
#bill = Bill.find_by( params )

Rails form_tag not displaying the existing field value

I've a settings controller setup like this:
class Admin::SettingsController < ApplicationController
def index
#settings = Setting.all
end
def update
setting_params.each do |key, value|
Setting.where(key: key).first.update_attribute :value, value
end
redirect_to admin_settings_path, notice: "Settings saved."
end
private
def setting_params
params.require(:settings).permit(:site_title, :site_desc)
end
end
The index action has a view file in relevant path, its code is as follows:
<h1>Settings</h1>
<%= form_tag admin_settings_path, method: "put" do %>
<p>
<label>Site Title:</label>
<%= text_field_tag "settings[site_title]" %>
</p>
<p>
<label>Site Description:</label>
<%= text_field_tag "settings[site_desc]" %>
</p>
<p>
<%= submit_tag "Save settings" %>
</p>
<% end %>
Now, I'm able to save/update these fields data in relevant model and I can see the data through command Setting.all in rails console. But the issue is, after saving the record via form when I reload the settings index page the form is blank and it is not showing previously saved values in the fields.
What I'm doing wrong here?
You can do what has been mentioned in the previous answer i.e. using a form_for. However, this can also be accomplished by creating a Hash in both the controller actions that creates and processes this form.
In the action that creates this form, the values in the hash could be initialized to blanks/zeros depending upon the input tag and in the action that processes this form, the values in the hash could be assigned to the values obtained from the posted params[].
I ran into the similar issue with form_tag and I used the following code in my index action i.e. the action that renders the form initially:
#search = {name: "", ranking_group: 0}
Whereas, in the search action, I used the following code to fill up this hash:
#search = {name: params[:name], ranking_group: params[:ranking_group]}
Finally, in the view, I used the appropriate default value options with the input tags as below:
<%= text_field_tag :name, #search[:name] %>
<%= select_tag :ranking_group, options_for_select(AmenityEntities::Amenity.ranking_group_options, #search[:ranking_group]), include_blank: true %>
Hope this helps.
I think you need to use form_for(#variable) instead of just a form_tag because you need to persiste the object after save.
form_for works with resources, take a look here: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html

Form submit doesn't update database

I am trying to create lists and each has 2 attributes name and description.Database does create it and save it when using console but not using the website form.When checking the log file I found that website form does not post instead uses gets and is redirected to itself, How do I make the website form POST instead of GET so it gets stored in database.
Log file:
Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at 2013-09-18 12:35:14 -0400
Served asset /jquery_ujs.js - 304 Not Modified (0ms)
Here is list controller:
def create
#list = Lists.new(params[:lists])
if #list.save
redirect_to #list
else
render 'new'
end
end
def update
if #list.update_attributes(params[:lists])
flash[:success] = "lists updated"
redirect_to #list
else
render 'edit'
end
end
def new
#list = Lists.new
end
This is the form for users to create list
<%= form_for #list, url: newlist_path(#list), html: { method: :put } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
</br>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.submit "Create the List" %>
<% end %>
Your form_for helper is routing to the incorrect action. Try routing to the create action instead:
<%= form_for #list, url: {action: "create"} do |f| %>
I don't know if your controller's code excerpt you've pasted is complete, but you might missed to initialize list object for update. In your update action you have only
if #list.update_attributes(params[:lists])
but you are not initializing #list variable before. So you probably need something like
#list = Lists.find(params[:id])
You can also inspect your log file and verify what parameters are sent to controller.

Passing all input as single params

I have created a search form
<%= form_tag url_for(:action => "index") do %>
<%= text_field_tag 'fromdate' %>
<%= text_field_tag 'todate' %>
<%= submit_tag 'Search' %>
<% end %>
I need to pass all these values as a single params in my controller to model. This is my controller
def index
#client = Customer.search
#something like this #client = Customer.search(as_single_params)
respond_to do |format|
format.html
end
end
How can I do this?
You can do this in your view:
<%= text_field_tag "some_fields[]" %>
<%= text_field_tag "some_fields[]" %>
<%= text_field_tag "some_fields[]" %>
Then in your controller simply retrieve the values using:
some_fields = params[:some_fields] # this is an array
If you pass values as keys, Rails will give you a Hash:
<%= text_field_tag "some_fields[fromdate]" %>
<%= text_field_tag "some_fields[todate]" %>
In your controller you can do this now:
#clients = Customer.search(params[:some_fields])
^
I added an s to #client since you'll have probably more than one clients matching your criteria.
When you submit your form, all of the parameters you selected will be passed to the controller in the params hash. For example, params[:fromdate] and params[:todate].
In your controller, if your params hash contains only Customer fields you want to search on (i.e., the form only has Customer fields defined, then you can do:
def index
#clients = Customer.where(params)
respond_to do |format|
format.html
end
end
Note that I show #clients since where will return a collection. You can select the first one (especially if you're sure there's only one) by doing this:
#client = Customer.where(params).try(:first)

Rails: what is the “correct” (idiomatic) way to pass a parameter from new to create in a RESTful controller?

I have a very common situation and a solution, but I would like to ask the Rails experts out there if it can be improved.
I have a very typical RESTful controller where the user supplies some of the object attributes upon creation. There is a thing model, a ThingsController and various views, including new, create, and a _form partial.
A thing has two attributes,
a color, which is set when they hit a link to create it (i.e. a “Create Red Thing” link that encodes the ID of red as a URL parameter)
a description, which is entered by the user in the form view
I’m happy with the approach for dealing with an attribute like the description that that a user specifies in the form, but less confident about the way that I handle an attribute that is passed through via the URL parameters associated with the first click.
This is what I am doing right now (note that I have omitted error checking to simplify matters). First, my new and create methods in the controller are as follows:
def new
#thing = Thing.new
#thing.color = Color. find(params[:color])
end
def create
#thing = Thing.new(params[:thing])
#thing.color = Color. find(params[:color])
if #thing.save
flash[:notice] = "Successfully created thing."
redirect_to somewhere_url
else
render :action => 'new'
end
end
The new view just invokes the _form partial, which looks as follows:
<% form_for #thing do |f| %>
<%= f.error_messages %>
<%= hidden_field_tag "color", #thing.color.id %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit "Submit" %>
<% end %>
It seems a little messy to be passing the color ID through to the create method as a URL parameter by putting a hidden field in the form. Does this look reasonable, or is there another approach that would be better?
Normally in this situation, I would put a hidden field in the form, which will hold the color_id. The nice thing about this way is that you can get by with just setting the color of the object before you render the form. So your controller changes to:
def new
#thing = Thing.new
#thing.color = Color. find(params[:color])
end
def create
#thing = Thing.new(params[:thing])
if #thing.save
flash[:notice] = "Successfully created thing."
redirect_to somewhere_url
else
render :action => 'new'
end
end
and your form will change to
<% form_for #thing do |f| %>
<%= f.error_messages %>
<%= f.hidden_field :color_id %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit "Submit" %>
<% end %>
The color is then passed through both forms, and you only need to retrieve the color in the first form. (Don't forget to add validations your Thing model to make sure it has a valid color though).

Resources