web-dev-qa-db-fra.com

Comment puis-je utiliser "Form_tag" par opposition à "Form_for" dans ce fichier

Je suis nouveau sur Ruby on Rails et j'ai été énormément aidé par l'excellent livre de Michael Hartl: Ruby on Rails Tutorial. Je suis arrivé au chapitre 8 et je suis maintenant sur les exercices de ce chapitre. J'ai un problème (je suppose un "débutant" typique) avec l'exercice 1. Dans cet exercice, il est demandé "1 .Refactor le formulaire de connexion pour utiliser form_tag à la place de form_for. "J'ai essayé de chercher de l'aide avec ceci dans Stackoverflow, Google, Railscast et de nombreuses autres" recherches sur le Web "depuis deux jours maintenant et je ne semble pas trouver l'aide que je dois répondre à ce problème. Le fichier que j'essaye de modifier avec form_tag est ci-dessous:

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

J'utilise Rails 3.2.3 dans cette application. Quelqu'un peut-il m'orienter dans la bonne direction? Quelqu'un peut-il m'aider avec ce problème? Je serais très reconnaissant.

Voici l'implémentation qui utilise 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>

J'utilise Rspec 2.9.0 et ci-dessous sont les tests qui échouent:

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 

et

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

et

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

Voici mon fichier de routes:

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
29
Tim Greider

Je viens de terminer cet exercice également, donc je ne suis en aucun cas un expert; cependant, c'est le code qui a fonctionné pour moi et a passé tous les 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>

J'ai également dû changer le ../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

Bien que cela fonctionne, je ne sais pas exactement pourquoi cela fonctionne; si quelqu'un pouvait expliquer pourquoi les changements dans le contrôleur sont nécessaires, ce serait très apprécié. Je sais que cela pourrait être posé comme une question distincte, mais elle est étroitement liée à OP et je suis sûr que nous trouverions tous les deux extrêmement utile pour comprendre non seulement comment faire en sorte que cela fonctionne, mais pourquoi cela fonctionne de cette façon. Voici les fichiers de vue et de contrôleur d'origine:

'Form_for' new.html.erb d'origine:

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

et le sessions_controller d'origine:

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
31
Tom

Les guides RoR expliquent comment fonctionne form_tag.

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

2
DVG

Je me suis fait prendre en ne nommant pas les champs correctement. Lorsque vous affichez la source de l'original, il vous montre le schéma de dénomination.

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

Vous disposez d'un Session_Helper que vous n'utilisez pas dans votre implémentation.

MODIFIEZ vos méthodes d'assistance.

  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

Ensuite, vous pouvez simplement utiliser les méthodes appropriées dans votre contrôleur de session. Il s'agit d'une mise en œuvre plus soignée qui suit l'approche modulaire de la conception. Il semble également qu'il y ait des problèmes avec 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) }

Même si tout est correct lorsque vous visitez la page, ces tests sont signalés. Je suppose que vous devez changer before do parce que s'il faisait ce que vous voulez qu'il fasse, les tests passeraient.

Quoi qu'il en soit, je suis curieux de savoir quel est le problème avec rspec si quelqu'un a une idée!

Je pense que ce problème est avec user.email.upcase. Vous n'avez pas besoin de .upcase, lorsque vous le supprimerez, les tests passeront.

1
user1556480