A copy action and copy.html.erb are defined in our rails 3.2 app. This copy action is to copy from the current record, allowing user modify slightly and submit for creation just like new. Here is the header of the copy.html.erb:
<%= form_for #engine_config, :as => :engine_config, :url => engine_configs_path do |f| %>
After clicking save, it hits create in controller and this is what we wanted.
Our question here is what the engine_configs_path stands for? Usually engine_configs_path is for index. Here the form is for create and is not index. What's the reasoning of this index path on create form?
When you do bundle exec rake routes you will see something similar to this;
engine_configs GET /engine_configs(.:format) engine_configs#index
POST /engine_configs(.:format) engine_configs#create
Which means engine_configs_path works with both GET for index controller action and POST for create controller action.
Therefore engine_configs_path refers to the url the form is posted to in the controller.
Form
You generally don't need to define the url argument in your form - Rails' form_for helper takes an initialized class object & extracts the required data for it automatically:
From the docs:
Typically, a form designed to create or update a resource reflects the
identity of the resource in several ways:
(i) the url that the form is
sent to (the form element's action attribute) should result in a
request being routed to the appropriate controller action (with the
appropriate :id parameter in the case of an existing resource)
(ii)
input fields should be named in such a way that in the controller
their values appear in the appropriate places within the params hash,
(iii) for an existing record, when the form is initially
displayed, input fields corresponding to attributes of the resource
should show the current values of those attributes.
In Rails, this is usually achieved by creating the form using form_for
and a number of related helper methods. form_for generates an
appropriate form tag and yields a form builder object that knows the
model the form is about. Input fields are created by calling methods
defined on the form builder, which means they are able to generate the
appropriate names and default values corresponding to the model
attributes, as well as convenient IDs, etc. Conventions in the
generated field names allow controllers to receive form data nicely
structured in params with no effort on your side.
--
Route
Your specific question is regarding the route your form_for method will use
As per w3c standards, HTML forms are defaulted to POST data. This means whenever you use a form_for helper in Rails, it will automatically use the POST variant of your routes
As described by Acacia, if you're using resourceful routes, you'll get a series of routes like this:
This means you can call the same route (engine_configs_path) with the HTTP Verb of POST to send to a specific controller#action, which is what's happening for you
The behaviour of engine_configs_path depends on the HTTP verb. That is, an HTTP GET to engine_configs_path will show the index; an HTTP POST to engine_configs_path will create a new one. form_for can check whether #engine_config exists in the DB or not via #engine_config.new_record?, so it knows to do a POST instead of a PUT.
Related
I'm trying to determine the best way to handle form submissions and routing.
I have the standard _form.html.erb, as well as new.html.erb and edit.html.erb - each renders form, subscription = #subscription, which is declared in the new and edit controller action.
The model is subscription, and this is my form element in _form.html.erb (it's in the checkout namespace) -
<%= form_for([:checkout, subscription]) do |f| %>
/checkout/subscriptions/new is the URL for a new subscription. When you submit the form, it posts to /subscriptions.
The problem is that if there are errors, and you refresh the browser (I know users will do this for one reason or another), you get an error message because there is no view for /subscriptions/index (I don't need one).
Same applies for editing. If you go to (as an example) /checkout/subscriptions/14/edit, everything's great. But if you submit the form, it posts to /subscriptions - same problem as with new - if you refresh the page, you get the no view error. This is the way Rails handles it with a new scaffold.
So my questions are:
what's the url I should use in the form_for tag?
what should I do for routing?
and how can I avoid this error when refreshing the page?
This is how the rails version of REST works (and should work). The key here is the HTTP method.
Reloading the page creates a GET request. While you controller should create resources with POST and update with PATCH/PUT.
GET requests should be idempotent (not create, alter or delete resources) so a GET request for /subscriptions or /subscriptions/:id is very different.
What can you do:
Use the window.beforeunload event in javascript to warn the user that they will lose data.
Route the GET /subscriptions path to subscriptions#new.
Route the GET /subscriptions/:id path to subscriptions#edit.
when using the following on routes.rb: resource :my_model
I get a few automatically generated routes. Some of them have a name (just like when manually defining them with 'as' keyword) but some of them don't.. so how can I give them names?
Or maybe it's a 'hint' given to me by rails that I'm not supposed to use these routes?
What do you refer to when you say "name", the Prefix when you run rake routes? Many of the HTTP requests (i.e. patch, put, delete) are handled by the controllers and are intended to then either redirect to another path or alter the DOM of the current page if you're using javascript, so they wouldn't have a prefix associated with them as those requests don't have an associated view.
When using a singular resource, all CRUD routes will be generated with the exception of an index route. You do not need names for these paths if you are looking to use them as intended. What is your intent for using these routes?
As per the docs:
A singular resourceful route generates these helpers:
new_resourceName_path returns /re/new
edit_geocoder_path returns /geocoder/edit
geocoder_path returns /geocoder
Please post your output via: bundle exec rake routes
You'll notice the show and create controller actions share the same path with the only difference being one expects a POST request and the other a GET request. This is some of the magic provided by Rails allowing you to use similarly named routes that map to different actions.
Try resources instead of resource. If you want a helper for PATCH, PUT or DELETE, just use the helper for the show action (that you'll get from resources) and specify the HTTP method with method:.
The second answer here has a decent explanation about your resource call.
These routes expect a different request method (this implies additional data in request), and do not need separate name, just use generic global_preferences_path and for example - set method for unobtrusive js in link:
<%= link_to 'Set preference', global_preferences_path(some_parameter:'foo'),
confirm:'Are you sure?', method: :put %>
or use html form or so
I am using form_for in the _form.html.erb view in order to create my form for both the edit and new actions, as per a standard scaffold.
I have a model Owner which has_many pets.
I would like to put an html link on my views/owners/show.html.erb to create a new pet for said owner. This link will point to the new action of pets_controller.rb which when accessed will render the view in pets/new.html.erb
What I want to happen is for the the owner_id to be passed with the link in the url to the new action of pets_controller.rb and then be used as the default for a collection_select in pets/new.html.erb
So I have a link to create a new pet but because that link was on a specific owner page, I want the form to create a new pet to have that owner already set, so the user does not have to select from the list.
This has to be done without changing the behaviour of the edit action/view in pets.
I know that I can pass GET arguments then access them in the controller via params, then create variables in the action which are passed to the view. I can then manually check for a default and set it in the view. I do not need assistance in coding if this is the only solution.
Is there is a better way to do this? A format with which I can pass the params such that the view will just pick them up? Without manually editing my controllers and views?
While my personal inclination would be to do as you said and pass a parameter in the link helper and then access the params array in the pets view, you may find that this is the perfect opportunity to explore Nested Resources. Essentially, you could declare owners/:owner_id/pets/:pet_id route with:
resources :owners do
resources :pets
end
You could then link to this route, and reference :owner_id without having to append the query string to the URI (making somewhat cleaner for reuse).
This is likely more work for you, but also potentially more extensible (and certainly more inline with the Rails way of doing things).
REVISION
Added the following regarding link helpers to the comments, but wanted to reflect it in the answer as well.
To show a pet should be:
<%= link_to owner_pet_path( owner_variable, pet_variable) %>
To view pets' index index should be:
<%= link_to owner_pet_path( owner_variable ) %>
The answer given to this question is fantastic.
As #ConnorCMcKee suggests it would be wise to consider nesting your routes. However, if you are a beginner as myself I found that it helped my learning to simply nest my second controller into the first (i.e. nest PetsController into OwnersController) as a first step. Then afterwards I would continue with the routes.
The method would be something like:
1./ In owners/index.html.erb:
Links to PetsController index action
The key to make this work is to send the :owner_id in your link parameters. Then that Pets index action will have access to that :owner_id and know which :owner_id called it.
2./ In PetsController you would then be able to find that Owner using that id, like so:
params[:owner_id]
Then your actions can start to take advantage of knowing what Owner called them. Remember though that all your redirects inside your PetsController need to preserve params[:owner_id]. That is because once you are inside that nested structure you have to maintain it and stay inside it and always know which :owner_id you are working with.
I have controller ArticlesController.
I have resource articles (in routes.rb file).
Why action articles#new corresponds GET /articles/new request and action acticles#create corresponds POST /articles request. Why not POST /articles/new ?
The new action displays a view in which you have a form that you fill out and submit. In this case, its a form for articles. This form could be anywhere on your website, but Rails convention holds that it is in your new page.
The create action takes the information you submitted in the form and tries to create an object. In this case, an article. This action does not, by convention, display a view, but redirects to another page. For me, it's usually the show page of that newly created article.
It's defined in the RESTful architecture that a POST request to a collection URI (e.g. "/articles") should create a new entry.
As already noted, the "/articles/new" URI is simply displaying the form, and it's not really an element URI (in the RESTful sense). Therefore it would be inproper to POST, PUT or DELETE it.
See http://en.wikipedia.org/wiki/Representational_state_transfer
I'm new to rails and still learning the ropes via railstutorial, but the book does all changes to the db via form submissions (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html). But how would I go about submitting (updating the db) without this, lets say I want to add some score which is computed on page ,(for example via a js counter - for simplicity lets just say its a constant 10) and my db consists of a column called score. Then after pressing a submit button how would I go about updating the db?
Thanks
Two trivial ways:
Use a form
Use a URL parameter with a link
The processing (other than GET v. POST) on the Rails side is identical--it's just a parameter.
If you're using JavaScript, there's not necessarily a reason to not use a form, though, since you could just update a form input element and submit normally.
It is quite simple, actually.
The constant 10 is submitted from the view. The submit needs to point to the controller action that will handle this request. So the submit button should build the url using :controller, :action, :id parameters. In a form, this is handled in the form_for declaration. You will deal with in the button_tag declaration.
The routes should be configured so that this message can reach the controller/ action.
The constant 10 is transported in the params hash. If the field is my_counter, then look for params[:my_counter]. If the form had been for a model, say tweets, then it might be in params[:tweet][:my_counter].
In the controller action, possibly update, you will first fetch the record to change with something like #score = Score.find(:params[:id]). This params[:id] is also coming from the view with the submit. Change the counter here, and save.
def update
#score = Score.find(:params[:id])
#score.counter = params[:my_counter]
#score.save
redirect_to :action => :index # or wherever
end
Good luck.