Rails Strong Parameters: How to accept both model and non-model attributes? - ruby-on-rails

I have a form to create a user model with all its usual attributes, but I am also passing a lot of non-model attributes that based on which I will create further stuff in my controller action.
My question is how I can tell Strong Parameters to accept both the user data, AND this other data that is not related to the user db wise?
To illustrate, my form could like this (submit button deleted for brievity):
<%= form_for #user do |f| %>
<%= f.text_field 'attribute1' %>
<%= f.text_field 'attribute2' %>
<%= f.text_field 'attribute3' %>
<%= text_field_tag 'attribute_not_on_user_model1' %>
<%= text_field_tag 'attribute_not_on_user_model2' %>
<% end %>
How can I use strong parameters to do this? I tried this:
params.require(:user).permit(:attribute1, :attribute2 , :attribute3, :attribute_not_on_user_model1,
attribute_not_on_user_model2)
And also this:
params.require(:user).permit(:attribute1, :attribute2 ,
:attribute3).require(:attribute_not_on_user_model1,
attribute_not_on_user_model2)
Both did not work. I am aware that I could do attr_accessor in the user, but I have a growing list of attributes in this form that are not related to the user model per se (but are nonetheless essential to the creation of the user model and its subsequent related models). We could debate that this is not the best way to do this (A form object comes to mind), but for the moment I want to see if Strong Parameters can help me here.

user model attributes are stored inside the :user hash, whereas the non-user attributes are accessible directly at the params level.
If you inspect your params Hash, you will notice that it is constructed in the following way
{ user: { attribute1: "value", attribute2: value, ... }, attribute_not_on_user_model1: "value", attribute_not_on_user_model2: "value" }
Consequently, the call
params.require(:user)
will automatically ignore any other param that is not part of the user node. If you want to include also the other params, you either compose the hash, or update the view to inject the params in the form.
Injecting the parameter on the form will cause the params to be part of the same :user node. This approach normally works very well with virtual attributes (despite the concepts are not linked each other).
<%= form_for #user do |f| %>
<%= f.text_field 'attribute1' %>
<%= f.text_field 'attribute2' %>
<%= f.text_field 'attribute3' %>
<%= text_field_tag 'user[attribute_not_on_user_model1]' %>
<%= text_field_tag 'user[attribute_not_on_user_model2]' %>
<% end %>
The other solution would be something like
def some_params
hash = {}
hash.merge! params.require(:user).slice(:attribute1, :attribute2, :attribute3)
hash.merge! params.slice(:attribute_not_on_user_model1,
attribute_not_on_user_model2)
hash
end
The solution, however, really depends on how you will user those params later. If all these params are sent as a single Hash, then you may want to compose the single hash, but in that case you may also want virtual attributes.
The point is that, without a real use case, the question itself is quite non-sense. StrongParameters is designed to filter a group of parameters passed to a bulk-create or bulk-update action. Generally, this means you have a model.
If you design a custom method, or if you have non-model methods, StrongParameters whitelisting may not have any sense, given you have control over the method you are writing and invoking.

There are many ways to do this and one way is with accecpts_nested_attributes_for: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Related

collection_check_boxes in Rails getting results from form

I find the documentation for
collection check boxes to be hard to understand. The explanation for the parameters is:
collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) public
Returns check box tags for the collection of existing return values of method for object's class. The value returned from calling method on the instance object will be selected. If calling method returns nil, no selection is made.
What I'm not sure about is what the "object" (the first argument) is supposed to be. I tried two different possibilities, and got different failures.
<%= collection_check_boxes(:wiki, :collaborating_user_ids, User.all, :id, :name) do |b| %>
<li>
<%= b.check_box %>
<%= b.label %>
</li>
<% end %>
The idea is that my app supports editing of wikis. I want the wiki owner to be able to add and remove users from the list of collaborators using checkboxes (which of course is only practical when there is a small number of users, which is the case). collaborating_user_ids is an instance method of Wiki that returns the current list of collaborators. I want to display the names of all users, with the current collaborators checked.
This works for the display, but when I inspect the params returned by this form, there is nothing showing which checkboxes were checked. On the other hand, if I replace the symbol :wiki by the instance variable #wiki, the checkboxes appear in the params associated with the wiki, but the checkboxes are not set correctly, initially.
I don't actually know what the first parameter of collection_check_boxes is supposed to be, but every example I've seen shows a symbol.
Assuming you have your associations set correctly.
The object should be the model that you are editing.
So yes, you are almost there. Make sure to include collaborating_user_ids inside your strong params in the wiki controller. This will allow the wiki to accept collaborators
# inside your wiki controller
class WikisController < ApplicationController
def wiki_params
params.require(:wiki).permit(collaborating_user_ids: [], ...)
end
end
Your form could look something like this
<%= form_for #wiki do |f| %>
<%= f.collection_check_boxes :collaborating_user_ids, User.all, :id, :name %>
<%= f.submit %>
<% end %>

Adding a confirmation checkbox to a form in Rails not tied to some attribute?

Noob question! :)
I have a form, that has basically no point other than call some_action. The reason I use a form for this, is because we have a specific styling for this in our large website.
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= f.save_button %>
<% end %>
I thought, since it's a form, I should be able to put a checkbox in there. It should have no other goal than confirming the user wants to do this action indeed. E.g. "Yes, I want to do some_action to the user model".
How would I make a checkbox that does not really change any attribute or affect anything - Other than that it should be checked for the form to submit?
This is probably dead simple, but according to the documentation and various error messages I should provide arguments such an attribute (which I don't want...)
form_for is meant to work on attributes of a model, which is what all the documentation you are reading is telling you. So if your model had a boolean column you could easily attach a check box to it.
If you ever want a form (or specific tag) that does not follow this, you can use the _tag version of these methods. For example, form_tag or, in your particular case, check_box_tag.
Example:
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= check_box_tag "do_some_method" %>
<%= f.save_button %>
<% end %>
NOTE: You will only get a param entry for :do_some_method if it is checked off. If you want to get a param regardless, you have to add a hidden_field_tag before it.
<%= hidden_field_tag "do_some_method", "no_dont_do_it" %>
<%= check_box_tag "do_some_method", "yes_do_it" %>
Now if the checkbox is selected you'll get params[:do_some_method] set to "yes_do_it"; if it's not checked off, instead of getting no entry, you'll get params[:do_some_method] set to "no_dont_do_it".

How to create one form from multiple unassociated (Not Nested) models in Rails 4?

I am using Rails 4 with postgres. Each model has an input form where users input parameters. Those parameters are then used to search a table. Each model has its own parameters unrelated to the others and own table to search. All the models then return a value from their respective tables. The models and their associated forms work just stand alone (I enter my parameters in model 1, and it searches the table for model 1 and returns the answer).
I am trying to create a series of pages that allow me to combine the models. For example, I want pages where a user can enter information in all 3 models, pages with just 2 of the 3 models, or perhaps even pages with two of the same model and a third different one. What is the best way to do this?
I have tried nested_attributes but am not sure it applies because I do not have associations. Am I missing something with that function that does allow it work in this use case? Thank you!
Here is a somewhat contrived example of a form containing several models, without nesting:
<%= form_tag(controller: "foo", action: "bar", method: :post) do %>
<%= fields_for(:subscriber, #user) do |sub_fields| %>
<div class="row">
<%= sub_fields.label :email %>
<%= sub_fields.text_field :email %>
</div>
<% end %>
<%= fields_for(#cat) do |cat_fields| %>
<div class="row">
<%= sub_fields.label :name %>
<%= cat_fields.text_field :name %>
</div>
<% end %>
<% end %>
Lets go over it from the top:
We use form_tag instead of form_for since we just want a form that is not bound to a resouce.
fields_for lets us bind inputs to any arbitrary resource.
The resulting params would be somthing like this:
{
subscriber: {
email: 'john.doe#example.com'
},
cat: {
name: 'Nisse'
}
}
See also:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
http://guides.rubyonrails.org/form_helpers.html
Take a look at the fields_for wrapper.
http://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for

Rails form for mailing

I'm trying to build a form which preloads content from two models (two variables being passed, being shown in the textfields) and then, not saves the data but sends the altered content (from the textfields) as two(?) variables to a mailer class.
I've managed to preload the data from one of the two models but am not sure how the form_for tag has to look like to get both models loaded as well as targeting the mailer class method instead of updating the model entity when pressing "send".
Do I need the accepts_nested_attributes_for attribute inside the model if I'm not saving anything?
I hope someone could give me an small example of the crucial parts. A thousand thanks!
You can use fields_for to include other models in same form. You can use it inside the same form_for what is present.
Checkout the example here from the api docs,
<%= form_for #person do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<%= fields_for #person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<%= f.submit %>
<% end %>
when you submit the data from this form, you can just use that data to pass to the mailer class from controller. UserMailer.get_user_info(params[:name], params[:address]).send
Creates a scope around a specific model object like #form_for, but doesn't create the form tags themselves. This makes #fields_for suitable for specifying additional model objects in the same form.
Refer Docs here:.
fields_for(record_name, record_object = nil, options = {}, &block)

Multiple value form tag for ruby

Here is the problem I'm having, and I have tried thinking around, but still can't figure out the solution. So I have two models
User
Data
and Experience belongs to user, and accepts nested attributes
Now here comes the problem ! I have page/form where I would like to update or insert.
so in the Data model
flavor, body
So How do I add form tag where I can specify my flavor but let user decide the body so for example, currently I have
<%= f.text_field :body, placeholder: "...." %>
So how do I do something like (wrong syntax)
<%= f.text_field :body, :flavor => "someflav" , placeholder: "...." %>
<%= f.text_field :body, :flavor => "Otherflav" , placeholder: "...." %>
and so on...
How does one achieve this ? I have looked around rails api, and but couldn't figure out how to achieve my issue.
Thanks for your consideration and time.
You need to use fields_for
Rails constructs input names that help it determine exactly what attribute goes where.
For instance:
user[datas_attributes][0][body]
Since (if I am interpreting you correctly) User has many Datas, it would look something like this:
<%= fields_for :datas do |data_fields| %>
<%= data_fields.text_field :body %>
<% end %>
There are a few things you need to do to make this work.
In your model, you need to add the following two lines:
accepts_nested_attributes_for :datas
attr_accessible :datas_attributes

Resources