2012-05-07 15 views
28

Sono nuovo a Ruby on Rails e sono stato aiutato immensamente dall'eccellente libro di Michael Hartl: Ruby on Rails Tutorial. Sono arrivato al capitolo 8 e ora sono sugli esercizi di quel capitolo. Sto avendo (presumo un tipico "newbie") problema con l'esercizio 1. In questo esercizio viene chiesto "1.Refactor il modulo di accesso per utilizzare form_tag al posto di form_for." Ho provato a cercare assistenza con questo in Stackoverflow, Google, Railscast e molte altre "ricerche web" per due giorni e non trovo l'assistenza di cui ho bisogno per rispondere a questo problema. Il file che sto cercando di modificare con form_tag è qui sotto:Come posso usare "Form_tag" invece di "Form_for" in questo file

<% 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> 

Sto usando Rails 3.2.3 in questa applicazione. Qualcuno può indicarmi la direzione corretta? Qualcuno può aiutarmi con questo problema? Sarei molto riconoscente.

Questa è l'implementazione che utilizza 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> 

Sto usando Rspec 2.9.0 e al di sotto sono le prove in mancanza:

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 

e

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 

e

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 

Ecco il file miei percorsi:

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 

risposta

28

Ho appena completato questo esercizio pure, quindi sono affatto un esperto; tuttavia, questo è il codice che ha funzionato per me e superato tutti i test:

../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> 

ho anche bisogno di cambiare il ../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 

Anche se questo funziona, non sono del tutto sicuro perché lo fa; se qualcuno potesse spiegare perché sono richiesti i cambiamenti nel controller, sarebbe molto apprezzato. So che questa potrebbe essere una domanda a parte, ma è strettamente correlata all'OP e sono sicuro che entrambi troveremmo estremamente utile capire non solo come farlo funzionare, ma perché funziona in questo modo. Di seguito sono riportati i file di visualizzazione e controller originale:

originale '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> 

e la sessions_controller originale:

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 
+1

FYI, nel SessionsController modificato, sono stato confuso da 'session [: user] = user.id' quindi l'ho rimosso e il mio test continua a passare e l'accesso ha esito positivo. – rda3000

+4

Se si guarda l'hash dei parametri effettivi, utilizzando form_for e form_tag si crea una struttura interna diversa. Quando si utilizza form_for, viene creato un hash nidificato all'interno dell'hash dei parametri. Questo hash contiene: email, ed è per questo che devi usare la sintassi params [: session] [: email]. form_tag, d'altra parte non crea un hash di sessione. Puoi accedere al campo email direttamente con params [: email]. –

2

Le guide RoR andare oltre come funziona form_tag.

http://guides.rubyonrails.org/form_helpers.html

+0

Grazie DVG. Ho avuto "inciampato" opon questa mattina. Dopo aver provato diversi esempi elencati in quella pagina (senza successo) ho pensato che o non capisco qual è il problema, o non si applica al mio caso. –

+0

Potrei suggerire di mostrare la tua implementazione fallita usando form_tag e quali problemi stai avendo in particolare? – DVG

+0

DVG, Il problema che sto avendo è con la mia prova. Quando lascio il codice come passano tutti i miei test. Quando sostituisco il form_tag ho fallito 10 test. Tutti i test falliscono a causa di "ActionView :: Template :: Error: Nessuna route corrisponde a {: action =>" destroy ",: controller =>" sessions "}" A causa del fatto che si tratta di un refactoring questo ovviamente non dovrebbe sta succedendo. Come faccio a mostrare la mia mancata implementazione in un commento? Grazie. @DVG –

15

Sto lavorando sullo stesso gradino del tutorial, e la tua domanda mi ha aiutato a trovare la mia strada.

L'uso di etichette e text_field, invece di label_tag e text_field_tag ​​sta lavorando bene, e non si dispone di modificare il codice di controllo (questo produce lo stesso codice HTML come con il metodo form_for originale).

<%= 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 %> 

È possibile leggere i dettagli in http://guides.rubyonrails.org/form_helpers.html#dealing-with-model-objects

1

Hai un Session_Helper che non si sta utilizzando nell'implementazione.

MODIFICA i tuoi metodi di supporto.

def sign_in(user) 
    cookies.permanent[:remember_token] = user.remember_token 
    session[:user_id] = user.id 
    end 

    def sign_out 
    cookies.delete(:remember_token) 
    session[:user_id] = nil  
    end 

Quindi è possibile utilizzare semplicemente i metodi appropriati nel controller di sessione. Questa è un'implementazione più ordinata che segue l'approccio modulare al design. Sembra anche che ci siano problemi con rspec.

describe "with valid information" do 
     let(:user) { FactoryGirl.create(:user) } 
     before do 
     fill_in "Email", with: user.email.upcase 
     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) } 

Anche se è tutto corretto quando si visita la pagina, questi test sono contrassegnati. La mia ipotesi è che è necessario cambiare before do perché se facesse ciò che si vuole fare i test passerebbero.

Ad ogni modo, sono curioso di sapere qual è il problema con rspec se qualcuno ha un'idea!

Penso che il problema sia con user.email.upcase. Non hai bisogno di .upcase, quando lo rimuovi i test passeranno.

1

Sono stato sorpreso a non nominare correttamente i campi. Quando visualizzi la fonte dell'originale, ti mostra lo schema di denominazione.

<%= form_tag(sessions_path) do %> 

    <%= label_tag 'session_email', 'Email' %> 
    <%= text_field_tag 'session[email]' %> 

    <%= label_tag 'session_password', 'Password' %> 
    <%= password_field_tag 'session[password]' %> 

    <%= submit_tag "Sign in", class: "btn btn-large btn-primary" %> 
<% end -%> 
Problemi correlati