Ruby on Rails, nested resource, use url id on submit - ruby-on-rails

So I have:
/projects/1/steps/new
When I submit a step, how do I save the project_id in step?
Do I need a hidden form field with "project_id", or can I set some other way?
As of now when submitted project_id get sets to nil

Make sure you are building the form as follows, to maintain the nested routing:
form_for [#project, #step]
Then, inside your StepsController you will receive a parameter :project_id.
HTH.

You can write in your controller create action:
#project.find params[:project_id]
#project.build params[:step]
In that case you don't need to pass hidden field.

Related

Example of form_for custom REST action and .haml?

I'm redeveloping a .haml form_for for an #edit_profile view to accommodate a controller where the #edit and #update methods have already been claimed. I had the form working before with the standard methods, but apparently Rails was doing a lot behind the scenes that I must now specify and I'm stuck.
I'm the sort who learns by mimicry and breaking things, so I need an example. I've googled around without any luck, so I'm hoping someone here can point me at one. Specifically: where do I put the method::patch and update_profile paths?
I just need the haml. I've established that the controller works with the new methods (#edit_profile and #update_profile), so all I have to do is connect the form to the controller.
Here's the repository if anybody needs that:
https://github.com/sidhene/MetPlus_PETS/blob/Update_CompanyPerson-%23146/app/views/company_people/edit_profile.html.haml
Thanks in advance,
A
The url argument needs to be to the update_profile action instead of the update action. Change update_company_person_path(#company_person) to update_profile_company_person_path(#company_person)
Edit: Your config/routes looks correct, but run rake routes just ot be sure. You should see a line with update_profile_company_person and PATCH in it.
form_for takes a value and populates its other HTML attributes from it (action / method etc):
form_for generates an appropriate form tag and yields a form builder object that knows the model the form is about.
As you see, the HTML reflects knowledge about the resource in several spots, like the path the form should be submitted to, or the names of the input fields.
The whole point of form_for is that you're meant to pass a resource / object to it.
Populated from the model, this object / resource will contain an array of data, such as the Class name etc, which Rails then uses to populate the form.
As per the docs:
...to create a new person you typically set up a new instance of Person in the PeopleController#new action, #person, and in the view template pass that object to form_for:
<%= form_for #person do |f| %>
The HTML generated for this would be (modulus formatting):
<form action="/people" class="new_person" id="new_person" method="post">
Thus, if you wanted to infer a different path / url for your form, you'll need to explicitly define it:
= form_for #profile, url: profile_update_path(#profile) do |f|
--
In your case, you're using a nested resource, which means that you have to pass both parts of the route as an array:
= form_for [:company_person, #company_person] do |f|
This should work fine for you.

Rails Forms for custom actions

I'm trying to link the input of a form to a specific action in my rails app.
Currently if I go to www.myapp.com/check/:idNumber, I'll be able to trigger the action just fine (which means routes is setup properly?). This action is basically a function call to a ruby/rails script with the parameter "idNumber" being passed to it. If the function is successful, it would return a newly created "Person" object and nil otherwise. This is different than the standard new operation as it determines the the attributes based on some information that it obtained from a database somewhere else.
Rake routes does give me the following:
check /check/:idNumber(.:format) person#check {:id=>/\d+/}
What I'm having trouble implementing is the form itself.
<%= form_tag("/check", :method => "get") do %>
<%= text_field_tag(:idNumber) %>
<% end %>
Controller action:
def check
regCheck = RegCheck.new
#person = regCheck.check_id(params[:idNumber])
if #person.name == nil
redirect_to root_path
end
end
submitting the form above would bring me to myapp.com/check?utf8=✓&idNumber=1234 instead. Can someone tell me what am I doing wrong?
I believe that using the check_path helper that is generated from the routes file is your best bet.
The form should look like this then.
<%= form_tag(check_path) do %>
<%= text_field_tag(:idNumber) %>
<% end %>
Rails forms can be finicky, especially when trying to build really customized forms.
This line
= form_for [#object]
Determines where the form goes, as well as the object that is being implemented. If you want to route the form to a different place, you can user the :url option. This options determines the path of the form, however you must keep in mind that the method is determined by the #object. If it is a new object, the method will be POST, an existing object will use a PUT method.
Let's suppose you want to update an existing object, but you want to send in data for a new object belonging to the existing object. That would look like
= form_for [#object], :as => #child_object, :url => my_optional_custom_path do |f|
# etc...
This generates a form sending a PUT request to the custom url (or the update path for #object if no custom url is supplied. The PUT request is sent with the parameter params[:child_object].
Hopefully this helps!
Best,
-Brian
I don't think it's possible the way you're trying.. The URL for the form is created before the user inputs any data.. So you need to remove the :idNumber from your routing..
If you do you get the following route:
check /check(.:format) person#check
Because the regex is removed now, you need to do this in you're controller:
def check
# Make sure ID is digits only
idNumber = params[:idNumber].gsub(/[^\d]/, '')
regCheck = RegCheck.new
#person = regCheck.check_id(idNumber)
if #person.name == nil
redirect_to root_path
end
end
You're form is allright, but you may want to use check_path like TheBinaryhood suggests..
If you really want it to be check/:idNumber you may also be able to submit the form to another action and redirect it to the right path from there..

how to add a `preview` action to resources?

I am looking for the right approach to include a preview action between new and create actions.
Let's assume I have the following:
resources :users
By default, when the form is submitted:
if new, call create action;
if edit, call update action.
In this way, I can use the same form (partial) for new and create, which is great!
How can I configure the resources to include a preview between actions. I mean, forcing new to call preview and then preview to call create.
I could add a new route/action and point the form for that action, however the same form cannot be used for new and edit.
There is a way to configure the resources to do that?
Have a look at this railscast: multibutton form, it shows a form with both a 'preview' and 'submit' button, maybe that's something you might want to do.
By the way, couldn't you use the same form by passing locals to the partial? For example:
<%= form_for #profile, url: dynamic_path do |f| %>
...
<% end %>
<%= render 'form', dynamic_path: profile_preview_path %>
you have several ways to do this:
you change the url of the form to your preview action (for which you have to add a route).
you use your create action for preview and create:
i.e. you add a parameter (like ':go_to_preview') to the form submit request. if you find it in the controller you render preview.
when the user wants to confirm the preview, you submit the data again (without that parameter) and this time create the record.
there are also 2 more dynamic possibilities:
you create the preview in real-time - if that is possible (like here on SO) - and use just the create action,
a variation of the first option: when the user submits the form, you send an ajax post request to a preview action, render a partial and include it on the page, then while your user still has the form he just filled, the user decides if she wants to modify or submit definitely.
I would suggest adding a DateTime column "finished_at", "published_on", etc... whatever is appropriate for your domain.
Using blog posts as an example:
scope :published, where("published_on IS NOT NULL")
scope :draft, where(:published_on => nil)
Use the scopes and new field where appropriate to limit the follow up actions.
This approach gives you more than you asked for :
a way to limit processing based on "state"
Data on creation times versus publishing times

Calling a method defined in a different controller when submitted form in Rails

I have a form_for tag specified as = form_for [#driver,#driver_availability].This stores the entered data in the driver_availabilities model and calls the create method of the DriversController.
Is it possible to make it call some method i define in a different controller but continue saving data in the driver_availabilities model as usual ?
Thank You
[#driver, #driver_availability] will call driver_driver_availabilities(driver_id: #driver) for new objects and driver_driver_availability(driver_id: #driver, id: #driver_availability) for existing driver availablities. So either you create a named route routing to the other controller (notice that these named routes are used for index, show, update and destroy as well) or you provide the url option to the form tag:
= form_for [#driver,#driver_availability], url: … # named route or routing hash
I would go with the second option.

Submitting custom information to a controller

This is probably simple, but I've tried a few things and couldn't find a way to make it work.
I would like to update a model with custom information given in a form_for
To make it more concrete, I'm on the show page for a particular instance of MyClass and I would like to pass something like the string "yay" into the controller, and then do as I please with the input. Maybe pass it back to the page as a flash message, or maybe modify the contents and then store it as a field of the MyClass instance.
I can write form_for's that contain the attributes of MyClass without prbolems, but it seems that other fields throw an error.
How do I write the form_for so that I can accomplish one of the two above scenarios?
def update
#my_class = MyClass.find(params[:id])
flash[:notice] = "This works" # but what can I write in a form for for it to be a variable that's passed in?
#rest of the update
end
Form helpers that unitize a form builder instance (like f.text_field) expect a valid model attribute so it can generate the appropriate id and populate the field with data from the model. If you want to have form fields that do not correspond to model attributes, don't use the the standard f.text_field but instead use:
<%= text_field_tag 'my_custom_tag' %>
which should render something like:
<input type="text" id="my_custom_tag"></input>
When the form is submitted, the value of the input will show up in the params hash with a key of :my_custom_tag.
I hope this helps.
It seems that you would probably need a hidden_field in your form :
http://apidock.com/rails/ActionView/Helpers/FormHelper/hidden_field
However, if you wish to save some kind of state, which seems like this is what you want, you would never use that. Instead, you would use a session. The reason is that a hidden field can be manipulated by the client and thus security can easily be overridden.
Like Spyros said, a hidden field will give you the place. Assuming you are ok with the fact that a user can modify the URL, just add attr_accessor :foo to your model.
In the controller you can access it with bar = params[:foo] and do as you please.

Resources