Form_For - Ruby on Rails

Setting up a form on Ruby on Rails where there is only an email to submit on a homepage without using the Devise gem

As per Rails and REST convention you shouldn't put the form in home.html.erb instead do the following,

In your users controller add new method and your controller will look like below,

class UsersController < ApplicationController

def new
@user = User.new
end

def create
@user = User.new(user_params)
if @user.save
redirect_to 'pages/success'
else
redirect_to 'pages/error'
end
end

private

def user_params
params.require(:user).permit(:email)
end

end

Now move your form to new.html.erb in users folder like below,

<%= form_for @user, url: users_path do |f| %>
<div class="wrapper">
<%= f.text_field :email , id: "search", class:"search input" %> <br />
<%= f.submit "yep", class: "submit input" %>
</div>
<% end %>

And don't forget to add routes,

root "users#new"

Also, model user.rb should have uniqueness validation

validates_uniqueness_of :email

form_for - Ruby on Rails

A little explanation ( form_for documentation here):

<%= form_for @user, :as => :user, :url => sign_in_path(@user) do |f| %>

Point 1. :as => :user

This is the name used to generate the input's name (and the params' names), example:

= form_for Admin.new, as: :user do |f|
#^^^^
= f.input :username

# will generate an input like this:
<input type='text' name='user[username]' #... />
#^^^^

Point 2. :url => sign_in_path(@user)

In the tutorial, @user is set like this:

  def sign_in
@user = User.new
end

Point 3. @user available in other actions

You have to set this variable in each action you want it. It can be redundant, so you can use a before_filter in order to authenticate set the @user variable at each action your want:

class UsersController < ApplicationController
before_filter :set_user_variable

def set_user_variable
@user ||= User.find(session[:user_id]) if session[:user_id].present?
end
end

If you want to make it available everywhere in your app (implies that you must be connected to a user account to browse the app):

class ApplicationController < ActionController::Base
before_filter :set_user_variable, except: [:sign_in, :login]

def set_user_variable
@user ||= User.find(session[:user_id]) if session[:user_id].present?
end

Point 4. form_for (User.new)

We set the variable @user in the controller and pass it as an argument to form_for because it is a Rails Convention to never call a Model's name directly in the views, and it is deprecated to provoke SQL queries in the view.

Example:

######## WRONG
# view
<%= Post.find(params[:id]).title %>

######## MUCH BETTER
# controller's action:
def show
@post = Post.find(params[:id])

# view
<%= @post.title %>

Instance Variables set in the Action of a Controller are shared between the actions, its view and its partial views.


Point 5. do/end block in form_for

Please give your input at this point, not sure how to explain it

This part of the code is called a do/end block, it represents a piece of code that will be executed in the context of the form_for. We use the form_for's instance as the variable defined in the pipes, here it is |f|. I usually don't use |f|, it is not really relevant to me. I prefer to use this kind of variable name:

= form_for @user do |user_form_builder|
= user_form_builder.input :username

Which I think is more readable and easier to understand.

how form_for works in Ruby on Rails

I didnt do that tutorial so mind me if i dont answer directly to your question.

Take a look at the rails guide about form helpers and it explains in details your questions, probably in a more articulate way than i can.

form_for(path/to/your/controller/action) is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action.

For example
In your controller

def new
@my_instance_variable = Myobject.new
end

In your view new.html.erb

<%= form_for @my_instance_variable do |f| %>
...
<% end %>

In your case the logic was directly written in the helper and you could also directly write

<%= form_for Myobject.new %>

Both will result with the following html

<form action="/myobjects/new" method="post">
# in this case rails knows its a `POST` request because the route new action
# is by default a POST request. You can check these routes and their request
# by using `rake routes` in terminal.

Then the hidden_field is another helper to contain a value, in your case the @user.id that will be passed as parameter then saved as a Create or update action for the given object. The reason it doesnt add the value in the hidden field tag is because you already have a model association that knows the id of user since the link of form uses the build method with user id.

Last part you need to understand the form_for link logic

current_user.relationships 
# implies the association of the current_user has many relationships
current_user.relationships.build
# .build is a method to populate a new object that can be save as a new record
# means you will create a new relationship record by populating the user_id
# column with the current_user.id and the followed_id with the target @user.id

Ruby on Rails form input

The HTML is generated by the Rails form helpers. Rails gives you a bunch of methods to make it easier to generate form markup so you don't have to worry about naming and typing out all of the attributes every time. Checkout that link to the docs to get more familiar.

How render form with previously entered data when validation fails

You are never setting the input's values. I'd suggest you use rails' form helpers like form_for and the rest. https://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object

<%= form_for @user do |f| %>
<%= label :username %>
<%= text_field :username %>
<%= label :email %>
<%= text_field :email %>
<%= label :password %>
<%= password_field :password %>
<%= submit %>
<% end %>

EDIT: there's even a section on the tutorial you linked that tells you to use form_for :S



Related Topics



Leave a reply



Submit