2 Stimmen

Schienen: Kommunikation zwischen View und Controller Frage (Theorie, Praxis, Antwort, alles!)

Ich brauche eine klare, leicht verständliche Antwort auf diese Frage. Ich baue ein Benutzer-Kontrollzentrum für administrative Benutzer zum Erstellen/Bearbeiten/Löschen von Benutzern des Systems über eine Weboberfläche (auf Authlogic und Rails-Autorisierung).

Auf der /users liste ich alle Benutzer auf, die ich dann nach Rollen aufgeschlüsselt habe.

Am Ende jeder Rollenliste befindet sich ein Link mit der Aufschrift "Neuen {Benutzertyp} hinzufügen".

Nun, was ich WILL, ist dies:

  • Wenn Sie auf den Link "Neuen {Benutzertyp} hinzufügen" klicken, werden Sie zum Formular "Neuer Benutzer" weitergeleitet, das auf diesen {Benutzertyp} zugeschnitten ist. app/controllers/users_controller.rb new Aktion.
  • Wenn das Formular falsch ausgefüllt wird, wird es mit den integrierten Validierungsformularen angezeigt, merkt sich aber, welche Art von Benutzer Sie erstellen wollten.

Ich habe versucht, dies zu tun, indem ich Parameter über den Link übergebe und dann auf sie über params[] aber ohne Erfolg. Meine Rollenzuweisungen sind NICHT Teil des Benutzermodells, was, wie ich weiß, die Dinge verkompliziert.

Wenn das Formular erfolglos abgeschickt wird, wird das Feld :type und gibt die (nicht maßgeschneiderte) Vanilleform wieder.

Kann sich jemand einen Reim darauf machen? Mir eine Richtung geben? Ich glaube, ich habe die relevanten Teile meines Codes unten wiedergegeben (jeder, der antworten möchte, um den Code zu bereinigen, wäre mir ebenfalls dankbar!)


Ansichten

app/views/users/index.html.haml :

.tabs
  %ul
    %li
      %a{ :href => '#all' }
        %span All Users
    %li
      %a{ :href => '#employees' }
        %span Employees
    %li
      %a{ :href => '#clients' }
        %span Clients
    %li
      %a{ :href => '#prospects' }
        %span Prospects
    %li
      %a{ :href => '#affiliates' }
        %span Affiliates
  #all
    = render :partial => 'users', :locals => { :users => @users, :type => 'All' }
  #employees
    = render :partial => 'users', :locals => { :users => @employees, :type => 'Employee' }
  #clients
    = render :partial => 'users', :locals => { :users => @clients, :type => 'Client' }
  #prospects
    = render :partial => 'users', :locals => { :users => @prospects, :type => 'Prospect' }
  #affiliates
    = render :partial => 'users', :locals => { :users => @affiliates, :type => 'Affiliate' }

app/views/users/_users.html.haml :

- if users.empty?
  %p{ :class => 'notice' }= "No #{type.pluralize} Found"
  %p{ :class => 'controls' }= link_to "Add a new #{type}", new_user_path(:type => type)
- else
  %table
    %tr
      %th Username
      %th Email
      %th Roles
    - users.each do |user| 
      %tr{ :class => cycle('even','odd') }
        %td=h user.username
        %td=h user.email
        %td= user.list_roles.collect{ |role| "<span class=\"role #{role}\">#{role}</span>" }.sort
        %td= link_to 'Edit', edit_user_path(user, :type => type)
        - if user.is_root?
          %td Can&rsquo;t delete root
        - else
          %td= link_to 'Delete', user, :confirm => 'Are you sure you wish to delete this user? This is irreversible!', :method => :delete
  %p{ :class => 'controls' }= link_to "Add a new #{type}", new_user_path(:type => type)

app/views/users/new.html.haml :

- title 'New User'
- form_for @user do |f| 
  = f.error_messages
  %ol{ :class => 'form' }
    %li
      = f.label :username
      = f.text_field :username
    %li
      = f.label :email
      = f.text_field :email
    %li
      = f.label :password
      = f.password_field :password
    %li
      = f.label :password_confirmation
      = f.password_field :password_confirmation
    %li
      - if @roles
        - @roles.each do |role| 
          = label_tag role
          = check_box_tag 'user[assigned_roles][]', role
      - else
        = hidden_field_tag 'user[assigned_roles][]', @type
    %li{ :class => 'submit' }
      = f.submit 'Register'
      = link_to 'cancel', @cancel

Steuerungen

app/controllers/users_controller.rb :

class UsersController < ApplicationController
  permit 'admin', :only => 'index', :get_user_method => 'current_user'

  def index
    @users = User.all
    @employees = find_all_users_with_roles(['root','admin'])
    @clients = find_all_users_with_roles(['client'])
    @prospects = find_all_users_with_roles(['prospect'])
    @affiliates = find_all_users_with_roles(['affiliate'])
  end

  def new
    @user = User.new
    @roles = get_all_roles
    @type = params[:type]
    @cancel = users_path
  end

  def create
    @user = User.new(params[:user])
    type = params[:type]
    roles = params[:user][:assigned_roles]
    if @user.save
      update_user_roles(@user,roles)
      if current_user.is_admin_or_root?
        flash[:message] = "User \"#{@user.username}\" created."
        redirect_to users_path
      else
        flash[:message] = "Congrats! You&rsquo;re now registered, #{@user.username}!"
        redirect_to app_path
      end
    else
      params[:type] = type
      render :action => 'new'
    end
  end

  ...

  private

  def get_all_roles
    roles = []
    Role.find(:all).each do |role|
      roles << role.name
    end
    roles
  end

  # code cleanup (using '.roles' ?)
  def find_all_users_with_roles(find_roles)
    users = []
    find_roles.each do |find_role|
      user_role_id = Role.find_by_name(find_role).id unless Role.find_by_name(find_role).nil?
      RolesUser.find_all_by_role_id(user_role_id).each do |role|
        users << User.find(role.user_id) unless users.include?(User.find(role.user_id))
      end
    end
    users
  end

  # cleanup - virtual attribute?? couldn't get that to work last time
  def update_user_roles(user,roles)
    # add new roles
    roles.each do |role|
      user.has_role role unless user.has_role? role
    end

    # delete roles
    (user.list_roles - roles).each do |role|
      user.has_no_role role
    end
  end

end

1voto

EmFi Punkte 23295

Da Sie nichts anderes gesagt haben und es richtig aussieht, gehe ich davon aus, dass das Anklicken eines "Add new #{type}"-Links so funktioniert, wie es sollte. Es sieht auch so aus, als ob Sie erfolgreich Benutzer erstellen können. Daher werde ich das Problem mit den fehlgeschlagenen Speicherungen angehen.

Der Controller rendert die neue Vorlage bei einer fehlgeschlagenen create-Aktion, definiert aber nicht die gleichen Instanzvariablen wie die neue Aktion. Wir müssen sie also erneut definieren. Ich habe sie in die create-Methode in der Fehlersperre . Ich habe auch eine subtile Änderung vorgenommen, die Ihr Formular sauberer macht.

app/controllers/users_controller.rb:

 def new
   @user = User.new
   @type = params[:type]
   @roles = get_all_roles.reject{|r| r.name == @type}
   @cancel = users_path
 end

 def create
    @user = User.new(params[:user])
    @assigned_roles = params[:user][:assigned_roles].select{|k,v| ! v.nil?}
    if @user.save
      update_user_roles(@user,roles)
      if current_user.is_admin_or_root?
        flash[:message] = "User \"#{@user.username}\" created."
        redirect_to users_path
      else
        flash[:message] = "Congrats! You&rsquo;re now registered, #{@user.username}!"
        redirect_to app_path
      end
    else
      @type = params[:type]
      @roles = get_all_roles.reject{|r| r.name == @type}
      @cancel = users_path
      render :action => 'new'
    end
  end

Mit dieser Änderung im Controller werden die Rollen zwar korrekt aufgelistet, aber der Typ wird nicht zugewiesen. Wir müssen also den form_for-Aufruf ändern, um den Parameter type an den create-Aufruf zu übergeben. Außerdem müssen wir das Formular so ändern, dass die ausgewählten Rollen nach dem Fehler erhalten bleiben. Indem wir type aus @roles im Controller entfernen, wird der angegebene Typ nicht im Formular aufgeführt. Er wird automatisch als hidden_field angewendet. Ich habe mir auch die Freiheit genommen, den Abschnitt um die Rollen-Kontrollkästchen herum umzustrukturieren, so dass das %li, das den Rollen-Abschnitt enthält, nur erscheint, wenn es Rollen zu zeigen gibt.

app/views/users/new.html.haml

- form_for @user, :url => {:action => :create, :type => @type) do |f| 
  %ol{ :class => 'form' }
    %li
      = f.label :username
      = f.text_field :username
    %li
      = f.label :email
      = f.text_field :email
    %li
      = f.label :password
      = f.password_field :password
    %li
      = f.label :password_confirmation
      = f.password_field :password_confirmation

    - if @roles
      %li
        - @assigned_roles ||= []
        - @roles.each do |role| 
          = label_tag role
          = check_box_tag 'user[assigned_roles][]', role, @assigned_roles.include?(role)

    = hidden_field_tag 'user[assigned_roles][]', @type
    %li{ :class => 'submit' }
      = f.submit 'Register'
      = link_to 'cancel', @cancel

Mit diesen schnellen Änderungen sollte alles so funktionieren, wie Sie es erwarten.

0voto

neezer Punkte 18458

Im Grunde alles, was EmFi vorgeschlagen hat, plus ein paar Änderungen:

app/views/users/new.html.haml

- if @roles
  %li
    - @assigned_roles ||= []
    - @roles.each do |role| 
      = label_tag role
      = check_box_tag 'user[assigned_roles][]', role, (@roles & @assigned_roles ).include?(role)

entfernt:

= hidden_field_tag 'user[assigned_roles][]', @type

(Der Parameter, den ich übertragen wollte, wird von geliefert:

- form_for @user, :url => {:action => :create, :type => @type) do |f| ...

Da ich es nur für die Präsentation verwendet habe, brauche ich es nicht im Formular zu speichern).

app/controllers/users_controller.rb:

def new
   @user = User.new
   @type = params[:type]
   @roles = get_all_roles # don't need to reject anything here either, since the :type is no longer part of this array
   @cancel = users_path
end

def create
   @user = User.new(params[:user])
   @assigned_roles = params[:user][:assigned_roles] # already has the roles I need; unchecked checkboxes are not passed into this; only checked ones
    if @user.save
      update_user_roles(@user,@assigned_roles)
      if current_user.is_admin_or_root?
        flash[:message] = "User \"#{@user.username}\" created."
        redirect_to users_path
      else
        flash[:message] = "Congrats! You&rsquo;re now registered, #{@user.username}!"
        redirect_to app_path
      end
    else
      @type = params[:type]
      @roles = get_all_roles # don't need to reject anything, since the :type is no longer part of this array
      @cancel = users_path
      render :action => 'new'
    end
  end

Danke, EmFi, dass Sie mich aufgeklärt haben! Die @assigned_roles Logik und

- form_for @user, :url => {:action => :create, :type => @type) do |f| ...

waren die Schlüssel zu diesem Rätsel, nach dem ich gesucht habe!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X