Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use "Form_tag" as opposed to "Form_for" in this file

I am new to Ruby on Rails and have been helped immensely by Michael Hartl's excellent book: Ruby on Rails Tutorial. I have gotten to Chapter 8 and am now on the exercises in that chapter. I am having ( I assume a typical "newbie") problem with exercise 1. In this exercise it is asked "1.Refactor the signin form to use form_tag in place of form_for." I have tried to searching for assistance with this in Stackoverflow, Google, Railscast, and many other "web searches" for two days now and I do not seem to find the assistance that I need to answer this problem. The file I am trying to modify with form_tag is below:

<% provide(:title, "Sign in") %> <h1>Sign in</h1>  <div class="row">   <div class="span6 offset3">     <%= form_for(:session, url: sessions_path) do |f| %>        <%= f.label :email %>       <%= f.text_field :email %>        <%= f.label :password %>       <%= f.password_field :password %>        <%= f.submit "Sign in", class: "btn btn-large btn-primary" %>      <% end %>      <p>New user? <%= link_to "Sign up now!", signup_path %></p>   </div> </div> 

I am using Rails 3.2.3 in this application. Can anybody point me in the correct direction? Can anyone help me with this problem? I would be most appreciative.

This is the implementation that uses form_tag:

<% provide(:title, "Sign in") %> <h1>Sign in</h1>  <div class="row">   <div class="span6 offset3">     <%= form_tag( url: sessions_path ) do  %>        <%= label_tag :email %>       <%= text_field_tag :email %>        <%= label_tag :password %>       <%= password_field_tag :password %>        <%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>     <% end %>      <p>New user? <%= link_to "Sign up now!", signup_path %></p>   </div> </div> 

I am using Rspec 2.9.0 and below are the failing tests:

describe "signin page" do     before { visit signin_path }      it { should have_selector('h1',    text: 'Sign in') }     it { should have_selector('title', text: 'Sign in') }   end  

and

describe "with invalid information" do             before { click_button "Sign in" }              it { should have_selector('title', text: 'Sign in') }             it { should have_selector('div.alert.alert-error', text: 'Invalid') }              describe "after visiting another page" do               before { click_link "Home" }               it { should_not have_selector('div.alert.alert-error') }             end       end 

and

describe "with valid information" do             let(:user) { FactoryGirl.create(:user) }             before do               fill_in "Email",    with: user.email               fill_in "Password", with: user.password               click_button "Sign in"             end              it { should have_selector('title', text: user.name) }             it { should have_link('Profile', href: user_path(user)) }             it { should have_link('Sign out', href: signout_path) }             it { should_not have_link('Sign in', href: signin_path) }              describe "followed by signout" do                     before { click_link "Sign out" }                     it { should have_link('Sign in') }             end       end 

Here's my routes file:

SampleApp::Application.routes.draw do   resources :users   resources :sessions, only: [:new, :create, :destroy]     get "users/new"    root to: 'static_pages#home'    match '/signup',  to: 'users#new'   match '/signin',  to: 'sessions#new'   match '/signout', to: 'sessions#destroy', via: :delete    match '/help',    to: 'static_pages#help'   match '/about',   to: 'static_pages#about'   match '/contact', to: 'static_pages#contact' end 
like image 980
Tim Greider Avatar asked May 07 '12 21:05

Tim Greider


People also ask

When would you use Form_for and when would you use form_tag?

form_tag simply creates a form. form_for creates a form for a model object. They are not interchangeable and you should use the one that is appropriate for a given case.

Which statement correctly describes a difference between the form helper methods form_tag and Form_for?

Which statement correctly describes a difference between the form helper methods form_tag and form_for ? The form_tag method is for basic forms, while the form_for method is for multipart forms that include file uploads.

What is the difference between Form_with and Form_for?

You use form_for with a model and form_tag for custom URLs. Both generate HTML for a form . There are only a few minor differences so Rails 5.1 combined the two. You should now be using form_with .

What are form helpers?

Forms in web applications are an essential interface for user input. However, form markup can quickly become tedious to write and maintain because of the need to handle form control naming and its numerous attributes.


2 Answers

I have just completed this exercise as well, so I am by no means an expert; however, this is the code that has worked for me and passed all the tests:

../app/views/sessions/new.html.erb

<% provide(:title, "Sign in") %> <h1>Sign in</h1>  <div class="row">   <div class="span 6 offset 3">     <%= form_tag sessions_path do %>        <%= label_tag :email %>       <%= text_field_tag :email, params[:email] %>        <%= label_tag :password %>       <%= password_field_tag :password %>        <%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>     <% end %>      <p>New User?<%= link_to "Sign Up Now", signup_path %> </p>   </div> </div> 

I also needed to change the ../app/controllers/sessions_contoller

class SessionsController < ApplicationController    def new   end    def create     user = User.find_by_email(params[:email])     if user && user.authenticate(params[:password])       session[:user] = user.id       sign_in user       redirect_to user     else       flash.now[:error] = 'Invalid email/password combination'       render 'new'     end     end    def destroy     sign_out     redirect_to root_path   end end 

Whilst this works, I'm not entirely sure why it does; if someone could explain why the changes in the controller are required it would be much appreciated. I know that this could be posed a s a separate question but it is closely related to OP and I'm sure we would both find it extremely useful in understanding not just how to get this to work but why it works this way. The following are the original view and controller files:

Original 'form_for' new.html.erb:

<% provide(:title, "Sign in") %> <h1>Sign in</h1>  <div class="row">   <div class="span6 offset3">     <%= form_for(:session, url: sessions_path) do |f| %>        <%= f.label :email %>       <%= f.text_field :email %>        <%= f.label :password %>       <%= f.password_field :password %>        <%= f.submit "Sign in", class: "btn btn-large btn-primary" %>     <% end %>      <p>New user? <%= link_to "Sign up now!", signup_path %></p>   </div> </div> 

and the original sessions_controller:

class SessionsController < ApplicationController    def new   end    def create     user = User.find_by_email(params[:session][:email])     if user && user.authenticate(params[:session][:password])       sign_in user       redirect_to user     else       flash.now[:error] = 'Invalid email/password combination'       render 'new'     end     end    def destroy     sign_out     redirect_to root_path   end end 
like image 54
Tom Avatar answered Sep 17 '22 14:09

Tom


I am working on the same step of the tutorial, and your question helped me finding my way.

The use of label and text_field, instead of label_tag and text_field_tag is working fine, and you don't have to change the controller code (this produce the same HTML code as with the original form_for method).

<%= form_tag(sessions_path) do %>   <%= label :session, :email %>   <%= text_field :session, :email %>    <%= label :session, :password %>   <%= password_field :session, :password %>    <%= submit_tag("Sign in", class: "btn btn-large btn-primary") %> <% end %> 

You can read details in http://guides.rubyonrails.org/form_helpers.html#dealing-with-model-objects

like image 28
Kood Avatar answered Sep 17 '22 14:09

Kood