Rails form for mailing - ruby-on-rails

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)

Related

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 Strong Parameters: How to accept both model and non-model attributes?

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

Rails - Multiple forms, different Models (Objects), one submit button

I have a view with 3 forms, Schedules, Workouts and Exercises, all behaving like an edit form, each. And one submit(save) button in the all the view.
When I click on the save button. Every data changed on those forms should be updated after click.
What is the best solution for this ? Javascript updating each data separated ? How to do that ? Is there a more Rails way to do this easily ?
My difficulty is how to integrated all those models in one view, while all this is happening in the show(view) from the Student model.
If you're implementing something like a profile / edit page (where you can save all the records at once), the two ways I would look at would either be to save the forms via Ajax, or use a single submit method to handle them
Ajax
The ajax method would be the most conventional:
Every form you submit will go to the form's own update method in the backend
Each form could be handled by a single button, but it's best to split them up
#app/controllers/profile_controller.rb
def edit
#schedules = Schedule.all #-> not sure how many records you're using
#workouts = Workout.all
#exercises = Exercise.all
end
#app/views/profile/edit.html.erb
<%= form_for #schedule do |f| %>
<%= f.text_field :test %>
<% end %>
# -> other forms
<%= button_to "Save", "#", id: "save" %>
#app/assets/javascripts/application.js
$("#save").on("click", function() {
$("form").submit(); // we'll have to define the form to submit
});
Single
If you submit all the forms as one, you'll have to encase them all in a single form, as sending different errors. This could be achieved by using _, and handled in the backend by looping through the different params, saving each one individually.
I'd do this:
#app/controllers/application_controller.rb
def submit
types = %w(schedules exercises workouts)
for type in types do
type.constantize.update_attributes()
end
end
This allows you to create a form with the different data types submitted in the same action:
#app/views/profile/edit.html.erb
<%= form_tag profile_submit_path do %>
<%= fields_for #schedules do |f| %>
<%= f.text_field :title %>
<% end %>
# -> fields_for for the other objects
<% end %>
This will allow you to send the updated objects to your controller, allowing them to submit
If all of your models (Schedules, Workouts and Exercises) are associated, using fields_for should be a good option.
From the above link:
<%= form_for #person do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<%= fields_for :permission, #person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<%= f.submit %>
<% end %>
Read the guides.
You could have some simple javascript that iterates over all form tags and submits each of them.
Alternatively, if you are going to use javascript anyways, you could follow an AJAXish auto-save approach upon changing any field.
But I think it might be cleaner if you just had one form for multiple models, using fields_for.

Form has_many in text_area

I have the following situation:
A Order has many Pages. I want to let the User to paste a bunch (20+) URLs (it's a Page attribute) that they might have in a doc file into a text area.
Right now I am not using a Form associated with an Order object, because I fail to see how I can do a nested form of the URLs if those are inside a text area.
I have seen a similar question has been asked before here: Rails: Using a Textarea for :has_many relationship , but I fail to see how would I code the view and model in order to do so.
So, if I have this:
Order has_many Pages
And a form like this:
<%= form_for #order do |f| %>
<%= f.text_area :page_urls?? %> # This would let the user paste X URLs, which would be
# used to create X Pages associated with the Order.
<% end %>
You could retain the view code that you have:
<%= form_for #order do |f| %>
<%= f.text_area :page_urls %>
#other field and submit button
<% end %>
In your model, you'll need to do the following:
attr_accessor :page_urls
after_validation do
if page_urls
parse_page_urls.each do |url|
pages.create(url: url)
end
end
end
def parse_page_urls
#use regexp to extract urls from page_urls string and return an array of url strings
end
The accessor is defined so that you can use :page_urls in your form_builder. You could set easily validations in your model for :page_urls that way too.
Once order has been validated, it will create page objects according to the number of urls extracted from the page_urls attribute.
You could refer to this for some help with using regexp to extract the urls from the string.
Hope that helps!
This is a job best handled with nested form. It will let you submit attributes of a has_many relationship model from the parent model, like you wish to do. For example, from its docs:
Imagine you have a Project model that has_many :tasks. To be able to use this gem, you'll need to add accepts_nested_attributes_for :tasks to your Project model. If you wish to allow the nested objects to be destroyed, then add the :allow_destroy => true option to that declaration. See the accepts_nested_attributes_for documentation for details on all available options.
This will create a tasks_attributes= method, so you may need to add it to the attr_accessible array (attr_accessible :tasks_attributes).
Then use the nested_form_for helper method to enable the nesting.
<%= nested_form_for #project do |f| %>
You will then be able to use link_to_add and link_to_remove helper methods on the form builder in combination with fields_for to dynamically add/remove nested records.
<%= f.fields_for :tasks do |task_form| %>
<%= task_form.text_field :name %>
<%= task_form.link_to_remove "Remove this task" %>
<% end %>
<%= f.link_to_add "Add a task", :tasks %>
In response to your comment:
In order to do something like that, you would need to do processing in the controller to separate the URL's, then make a new Page object associated with #order object. Unfortunately, there isn't a way to do this without post-processing, unless you do it with JS on the client side with hidden inputs.

Why this error in Three Level nested attributes in Rails 3?

this error not display on creation of record
only come when update
please help..
Your code in edit template seems to be the source of this problem. You must have defined member's last_name without using the fields_for object.
<%= f.fields_for :member do |member| %>
<%= member.text_field :first_name %>
... # Other attributes
<%= member.text_field :last_name %> # make sure you are using the fields_for instance (member in this example) here.
<% end %>
add attribute to attr_accessible list like
attr_accessible attr1, attr2
this is rails 3 technique to avoid unwanted attribute assignments like sensitive data from form.
Is applicable while using object.update_attributes function and note with object.save.

Resources