Ruby on Rails access whole params hash - ruby-on-rails

I have an application that deals with user rotas - and I'm currently adding the ability for admin approvals. If the user updates their own rota the params hash looks something like:
Parameters: {id:1, role_id: 1, team_id:1, rota: [startDate: 01/01/2014, endDate:02/02/2014]}
and these are submitted using a form with:
<%= form_for [#team,#role,#rota] do |f| %>
form code
<% end %>
We need to access the attributes outside the rota: object but currently can't find a way to as:
params.require requires you to pass an object in.
My team members have decided to add hidden fields to submit the attributes within the rota object but that seems redundant seeing as they are quite clearly there, we just can't find a way to access them, and ideas?

I was talking about something like
def user_rota_params
params.require(:user)
.permit(:role_id, :team_id, :rota => [:startDate, :endDate])
end
Then, for your nested attributes you could use fields_for.
Your form, thus, should look something this (omitting labels and keeping it basic):
<%= form_for #user do |f| %>
<%= f.text_field :role_id %>
<%= f.text_field :team_id %>
<%= f.fields_for :rota do |ff| %>
<%= ff.date_field :startDate %>
<%= ff.date_field :endDate %>
<% end %>
<% end %>

Related

Pass non model parameter to controller action

How do I pass those arguments which are not of model to a controller?
script.rb
class Script < ActiveRecord::Base
attr_accessor :directory
attr_accessor :xmlFile
end
show.html.erb
<h1><%= #script.Name %></h1>
<%= simple_form_for #script, :url => script_execute_path(script_id: #script.id) do |f| %>
<%= f.input :directory %>
<%= f.input :xmlFile %>
<%= f.button :submit, 'Run' %>
<% end %>
Here directory and xmlFile are used for taking inputs but it is not a part of Script model. Now I need to pass values contained in directory and xmlFile to my execute controller action
def execute
#script = Script.find(params[:script_id])
#something like this -- #xmlFile = params[:xmlFile]
end
how do I access it here?
They are indeed part of the Script model, because they are defined as attributes of the model. The fact they are not persisted is irrelevant.
You access them from the hash of params that represent the model itself. You can determine the exact name inspecting the logs of the request, you'll see how the parameters are structured.
Assuming the name of the model is Script, the hash key that contains the script attributes should be called script, therefore:
params[:script][:directory]
Please note that Ruby doesn't use camelCase, therefore the name xmlFile doesn't follow the conventions and may cause you issues. The name should be xml_file, not xmlFile.
For arbitrary fields that aren't part of a model, you can use Rails' standalone tag helpers, such as text_field_tag:
<%= simple_form_for #script, :url => script_execute_path(script_id: #script.id) do |f| %>
<%= text_field_tag :directory %>
<%= text_field_tag :xmlFile %>
<%= f.button :submit, 'Run' %>
<% end %>
If you want to pre-fill them with an existing value, you can pass that in as well:
<%= text_field_tag :directory, 'some default value' %>
It looks like you've actually already figured it out. By declaring
attr_accessor :directory
attr_accessor :xmlFile
in your Script model, you've effectively made them a part of the model. They just won't be persisted to the database when the object is saved. But as long as the object is in memory, those attributes will be available.
And since you've already got those attributes defined in your view:
<%= f.input :directory %>
<%= f.input :xmlFile %>
they'll be available to you in your controller via the params hash via params[:directory] and params[:xmlFile].

Form for each user

I have an ordinary form to create a Package object at /packages/new:
<%= form_for #package do |f| %>
<%= f.text_field :name %>
<%= f.text_field :address %>
...
<% end %>
The package model belongs_to :partner.
I am looking for a way to associate a new package form to a specific partner, preferably without any input from the user filling it in.
For example, if partner A sends a link to the form, I want the form to include partner_id:A.id.
How can I connect forms to partners?
You can send partner_id param with the link which your partner will send.
Something like
http://website.com/packages/new?partner_id=3
And use the param as hidden_field in the form
<%= form_for #package do |f| %>
<%= f.text_field :name %>
<%= f.text_field :address %>
<%= f.hidden_field :partner_id, value: params[:partner_id] %>
...
<% end %>
Alternatively you can also make use of Nested Resources
you can have, hidden field which passes partner_id to controller
http://apidock.com/rails/ActionView/Helpers/FormHelper/hidden_field
If the partner needs to be logged in, in order to create a package, you could simply link the package to the partner in the controller right before saving it.
As mentioned before, use params. And don't forget to allow the required params in the controller if necessary (via link, scroll down a little). documentation: params
Check out what e.g. .build() does for you. more about relations and how to set them up correctly

Rails multi-record form only saves parameters for last record

I'm trying to offer teachers a form that will create multiple students at once. It seems that most people tackle this concept with nested attributes, but I'm having a hard time understanding how that would work when I'm only using a single model. This article made it seem possible to achieve this without nested attributes, but my results are not working the way the author suggests. The students array should include one hash for each section of the form. But when I submit the form and check the parameters, only one single hash exists in the array.
Adjusting her approach, I've got this controller:
students_controller.rb
def multi
#student_group = []
5.times do
#student_group << Student.new
end
end
(I'm using an action I've called "multi" because it's a different view than the regular "create" action, which only creates one student at a time. I've tried moving everything into the regular create action, but I get the same results.)
The view:
multi.html.erb
<%= form_tag students_path do %>
<% #student_group.each do |student| %>
<%= fields_for 'students[]', student do |s| %>
<div class="field">
<%= s.label :first_name %><br>
<%= s.text_field :first_name %>
</div>
<div class="field">
<%= s.label :last_name %><br>
<%= s.text_field :last_name %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
The results:
(byebug) params
<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"3Xpi4XeqXuPs9jQvevy+nvGB1HiProddZzWq6Ed7Oljr3TR2fhx9Js6fN/F9xYcpgfDckCBOC2CoN+MrlFU0Bg==", "students"=>{"first_name"=>"fff", "last_name"=>"ggg"}, "commit"=>"Save changes", "controller"=>"students", "action"=>"create"} permitted: false>
Only one has is included for a student named "fff ggg". There should be four other hashes with different students.
Thank you in advance for any insight.
fields_for is only used in conjunction with form_for. The for is referring to a model, which it expects you to use. Since you're trying to build a form with no model, you have to construct your own input field names.
Don't use fields_for but instead, render each input using the form tag helpers e.g.
<%= label_tag "students__first_name", "First Name" %>
<%= text_field_tag "students[][first_name]" %>
...and so on.
The key is that the field names have that [] in them to indicate that the students parameters will be an array of hashes. You almost got it by telling fields_for to be called students[] but fields_for ignored it because it needs a model to work correctly.

Rails issue with access of nested hash parameter

I have in rails the following form in a view
<%= form_for (#account) do |f| %>
<%= f.label :comments,"Comments" %>
<%=f.text_area :comments %>
<%= f.submit "Confirm",:name=>"conf" %>
<%= f.submit "Reject" %>
<% end %>
When I submit the form I get the following hash in the log before the update of the database
Started PATCH "/accounts/12" for 127.0.0.1 at 2015-08-13 21:31:18 +0200
Processing by UseractionsController#answer_with_comments as HTML
Parameters: {"utf8"=>"✓", "account"=>{"comments"=>"mycomments"}, "conf"=>"Confirm", "id"=>"12"}
I am trying to access the input in the comments text area in the controller. I tried
params[:account][:comments]
but it does not seem to work. Could anyone give me the appropriate syntax? Thanks.
EDIT
This is my controller code. Right now the if loop return false and nothing is added to the database even though there is something submitted ("mycomments" see above in the param nested hash)
if params[:bankaccount][:comments]
#bankaccount.update_attribute(:comments, params[:bankaccount][:comments])
end
It is only the appropriate syntax for your view. It assumes that you have content field on your Comment model.
<%= form_for (#account) do |f| %>
<%= f.label :comments,"Comments" %>
<%= f.fields_for :comments do |ff| %>
<%= ff.text_field :content %>
<% end %>
<%= f.submit "Confirm",:name=>"conf" %>
<%= f.submit "Reject" %>
<% end %>
You also will have to declare nested attributes in your Account model and your params hash should be different.
You should watch these two Railscasts part 1 and part 2 to learn more about nested attributes.
Since you mention strong parameters as a tag you probably want to build this a bit differently.
private
def account_params
#the permit method might need to be altered depending on your model and view
params.require(:account).permit(:comments)
end
Somewhere else in your controller you would then do:
#bankaccount.update_attributes(account_params)
Please take a read: http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters

virtual model and form_for (or formtastic)

Sometimes we need form without model creation - for example search field or email, where should be send some instructions. What is the best way to create this forms? Can i create virtual model or something like this? I'd like to use formtastic, but not form_tag.
Firstly, Formtastic doesn't need a model in all cases, although it certainly works best and requires less code with a model.
Just like Rails' own built-in form_for, you can pass in a symbol instead of an object as the first argument, and Formtastic will build the form and post the params based on the symbol. Eg:
<% semantic_form_for(:session) do |f| %>
...
<% end %>
This will make the form values available to your controller as params[:session].
Secondly, a model doesn't mean an ActiveRecord model. What I mean is, Formtastic will work with any instance of a class that quacks like an ActiveRecord model.
A classic example of this that many people are using Authlogic for authentication with Formtastic. Part of Authlogic is the idea of a UserSession model, which works fine:
Controller:
def index
#user_session = UserSession.new
end
Form:
<% semantic_form_for(#user_session) do |f| %>
<%= f.input :login %>
<%= f.input :password %>
<% end %>
This will make your form data available in your controller as params[:user_session].
It's really not that hard to create a model instance to wrap up the concerns of your model. Just keep implementing the methods Formtastic is expecting until you get it working!
default_language.rb
class DefaultLanguage
attr_accessor :language_id
end
foo_controller.rb
def index
#default_language = params[:default_language] || Language.find_by_name("English")
end
index.erb
<% semantic_form_for #default_language do |form| %>
<% form.inputs :id => 'default_language' do %>
<%= form.input :id,
:as => :select,
:collection => #languages,
:required => false,
:label => "Primary Language:",
:include_blank => false %>
<% end %>
<% end %>
I used AJAX to post the form when the value changed.
Or you simply create a form with form_for and leave the model reference blank.
for example
<% form_for "", :url=>some_url do |f| %>
<%= f.text_field "some_attribute" %>
<%= submit_tag "submit" %>
You can fetch the values by simply saying params[:some_attribute] in your controller.

Resources