Understanding function form_for() in Rails - ruby-on-rails

I'm currently reading Beginning Rails 3. I'm coming from PHP and trying to learn Ruby and Rails. I'm looking at a _form partial and I have a few questions. Specifically about the line:
<%= form_for(#article) do |f| %>
What is the purpose of having the #article object in there as well as what is the function of variable f?
thanks,
mike

form_for accepts a model so that it can do a few things for you under the covers:
It will read any current values off of that model and populate them in the fields you specify
It will generate the proper URL for that resource (assuming you're following conventions, otherwise you still have to specify it)
It can display any validation errors on the model if you're displaying after a POST.
If you just want the tag helpers, there's also form_tag and friends

The #article is what the form is for (in this case).
The f is for creating individual form elements; it's a builder object yielded by form_for's block.

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.

ruby on rails 4.2 - ActionController::UrlGenerationError in Prodotti#new

I'm following the tutorial http://guides.rubyonrails.org/getting_started.html but i'm stuck on section 5.2 'the first form'
The error is after i put prodotti_path
<%= form_for :prodotto, url: prodotti_path do |f| %>
my rake routes:
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
prodotti_index GET /prodotti(.:format) prodotti#index
POST /prodotti(.:format) prodotti#create
new_prodotti GET /prodotti/new(.:format) prodotti#new
edit_prodotti GET /prodotti/:id/edit(.:format) prodotti#edit
prodotti GET /prodotti/:id(.:format) prodotti#show
PATCH /prodotti/:id(.:format) prodotti#update
PUT /prodotti/:id(.:format) prodotti#update
DELETE /prodotti/:id(.:format) prodotti#destroy
root GET / welcome#index
but when i refresh the page http://localhost:3000/prodotti/new/ the rails say:
ActionController::UrlGenerationError in Prodotti#new
Why? i'm new to ruby and ror, sorry !
Firstly, welcome to the Rails community!
Here's what you need to do:
#app/controllers/prodottis_controller.rb
class ProdottisController < ApplicationController
def new
#prodotti = Prodotti.new
end
def create
#prodotti = Prodotti.new prodotti_params
end
private
def prodotti_params
params.require(:prodotti).permit(:x, :y, :z)
end
end
Then in your view:
#app/views/prodotti/new.html.erb
<%= form_for #prodotti do |f| %>
<%= f.text_field :attribute_name %>
<%= f.submit %>
<% end %>
OOP
The problem you have is you're using a symbol in your form_for. Whilst this does work, it is not the best way to get it working, especially for a beginner.
Without going into too much detail, I'll explain that form_for is what's known as a helper method. If you pass this certain credentials, it will construct an HTML form for you:
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,
and (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.
This basically means that you're meant to pass objects to the form_for helper - objects which have been built in your model and assigned in your controller.
The objects in Ruby are used by Rails throughout your application. Indeed, as Ruby is object orientated, all the things you do with the language, and frameworks, are meant to revolve around objects too.
Rails is object orientated in its own way. Remember, Rails is a framework which sits on top of Ruby. Thus, anything you do has to have objects at the center of the flow:
Models construct the objects in Rails.
Everything from your routes to controller actions take the idea that your models will be invoking data objects -- making it that each "helper" method in Rails (such as form_for) can be used with the corresponding objects you've built.
This is why I recommended setting the appropriate variable and passing it to your form helper. This will tie into your routes and controller actions, and should work for you.

rails g scaffold needs explanation - form_for submits to index?

I am trying to understand the stuff going on during the creation of an object using the pages generated by the command rails g scaffold ModelName.
What I don't understand is that given a model Location, the _form.html.erb form-tag looks like this:
<%= form_for(#location) do |f| %>
This would, if I understand it correctly, point the form submission to location_path, which is like the index (or list) of all locations stored in the database.
Why is the form not pointing to create or update? Where on the way are the objects actually created? I'd be really grateful if someone could describe the flow here, like
_form.html.erb submits to
create in locations_controller.rb which redirects to
index in locations_controller.rb, which renders
sometemplate.html.erb
Where the form submits depends on #location.new_record?.
If it’s a new record, it will POST to locations_path: /locations. That maps to LocationsController#create.
If it’s an existing record, it will PUT (or PATCH on newer versions of Rails) to location_path(#location): /locations/:id. That maps to LocationsController#update.
As #Pavan suggests in the comment, a look at the existing routes can help with understanding routing:
rake routes

Rails nested forms - how to only submit the inner form when using form_tag

Say you have nested forms in rails, which is only nested to accomodate the layout (in other words have nothing to do with each other, and should be submitted completely seperately)
for example
= form_tag update_custom_stock_admin_shop_products_path(#current_shop), method: 'put' do
...
...
= form_tag change_range_admin_shop_products_path(#current_shop), remote: true do
...
submit_tag 'change'
...
...
submit_tag 'submit'
How do I ensure that only the inner form is submitted when the inner submit ('change') is clicked, and the same for the outer form.
And please, do not tell me to use form_for instead. Because I am using custom parameters and interpreting them manually with params. If you do not know the answer, I kindly ask that you ignore my question and do not downvote or tell me it's better to use form_for
Nested forms don't really work. According to the html5 spec you shouldn't have them at all. You can have multiple forms per page though. You'll probably need to rethink the logic and use multiple remote forms.
Here's the html5 spec: https://www.w3.org/TR/html5/forms.html#the-form-element. Note:
4.10.3 The form element
Content model:
Flow content, but with no form element descendants.

New to Rails: How to pass arguments from a textbox to another controller?

I am new to Rails and don't quite understand what I'm supposed to do. Let's say, for example, I want a textbox containing a string to be passed into another controller (another page?) when the user clicks a button. How would I go about doing that?
Functions of controllers are pages, correct? Can a function take parameters just like a normal method? (E.g. sum(x,y))
For complete information, check out Rails Form helpers. Basically, you give the form_tag method a path which points to the controller and the action that you want to handle the form submission. For example,
<%= form_tag(search_path, :method => "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
Here, the action and controller that search_path points to (defined in your routes) will receive the form submission and the value from the text field.
Your action in the controller IS a function, but it will not receive the value from the form submission as a parameter to the function. Instead, you will access it through the params hash. In the example above, you can access the value from the text field as
params[:q]
What are you doing with the string? Storing it? Using it as a parameter on another page?
I suggest you take a look at the Getting Started Guide, go through it, and pay particular attention to the What is Rails? section, where it explains MVC architecture and REST (Representational State Transfer.)
There are dozens of other Rails tutuorials out there, I'm sure if you searched this site you'd find many questions like this one:
https://stackoverflow.com/questions/2794297/how-to-learn-ruby-on-rails-as-a-complete-programming-beginner
Functions of controllers are pages, correct? Can a function take parameters just like a normal method?
Functions of controllers are pages if that's the route you've set up in your routes.rb configuration file. I suggest you run through some tutorials to understand what Rails is for and how it works.

Resources