Rails:View&Controller问题之间的沟通(理论,实践,答案,任何事情!)

我需要一个直截了当,易于理解的答案。 我正在为管理用户构建一个用户控制面板,通过Web界面创建/编辑/删除系统用户(在Authlogic和rails-authorization上)。

/users视图中,我列出了所有用户,然后根据角色对其进行了细分。

在每个角色列表的末尾,我都有一个链接“添加新{用户类型}”。

现在,我想要的是:

  • 单击“添加新{用户类型}”链接后,您将进入针对该{用户类型}定制的新用户表单,所有这些都使用app/controllers/users_controller.rb new操作。
  • 如果表单填写不正确,它将显示内置validation表单,但记住您尝试创建的用户类型。

我试过通过链接传递参数,然后通过params[]访问它们,但没有运气。 我的角色分配不是用户模型的一部分,我知道这会让事情变得复杂。

目前,无论何时提交表单失败,它都会删除:type ,并呈现vanilla(非定制)表单。

任何人都能做到这一点的正面或反面吗? 给我一些指导? 我相信我已经在下面复制了我的代码的相关部分(任何想要回答清理代码的人,我也很感激!)


查看

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| "#{role}" }.sort %td= link_to 'Edit', edit_user_path(user, :type => type) - if user.is_root? %td Can’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 

控制器

app/controllers/users_controller.rb

 class UsersController  '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’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 

正如你没有说的那样,它看起来是正确的,我将假设单击“添加新的#{type}”链接可以正常工作。 看起来您也可以成功创建用户。 因此,我将继续解决不成功保存的问题。

控制器在失败的创建操作上呈现新模板,但不定义与新操作相同的实例变量。 所以我们需要再次定义它们。 我已将它们添加到故障块中的create方法中。 我也对新的做了一个微妙的改变,使你的forms更清洁。

应用程序/控制器/ 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’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 

但是我们只是完成了一部分,只需在控制器中进行更改,我们就会正确列出角色,但不会分配类型。 所以我们必须修改form_for调用以将type参数传递给create调用。 我们还需要更改表单,以便在失败后保留角色。 通过从控制器中的@roles中删除类型,指定的类型未在表单中列出。 它会自动应用,作为hidden_​​field。 我也冒昧地围绕角色复选框重构部分,以便只有在要显示的角色时才会显示包含角色部分的%li。

应用程序/视图/用户/ 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 

通过这些快速变化,事情应该按照您的预期进行。

基本上所有EmFi建议,加上一些调整:

应用程序/视图/用户/ 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) 

删除:

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

(我想要携带的参数由以下提供:

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

由于我只用它来演示,我不需要将它存储在表格中。)

应用程序/控制器/ 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’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 

谢谢,EmFi,让我直截了当! @assigned_roles逻辑和

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

是我正在寻找的这个难题的关键!