Rails: Communication between View & Controller question (theory, practice, answer, anything!)

后端 未结 2 1849
伪装坚强ぢ
伪装坚强ぢ 2021-01-07 00:04

I need a straightforward, easy to understand answer on this one. I\'m building a user control panel for administrative users to create/edit/delete users of the system throu

2条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-07 00:51

    As you haven't said otherwise and it looks right, I'm going to assume that clicking an "Add new #{type}" link works as it should. It also looks like you can successfully create Users. So I'm going to move on to address the problem with unsuccessful saves.

    The controller renders the new template on a failed create action, but doesn't define the same instance variables as the new action. So we need to define them again. I've added them to the create method in the failure block. I've also made a subtle change to new that will make your form cleaner.

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

    However we're only part way done, with just that change in the controller we'll list the roles properly, but the type won't be assigned. So we have to modify the form_for call to pass the type parameter to the create call. We also need to change the form so it keeps roles selected after the failure. By removing type from @roles in the controller, the specified type isn't listed in the form. It's automatically applied, as a hidden_field. I've also taken the liberty of restructuring the section around the roles checkboxes, so that the %li containing the roles section only appears if there are roles to show.

    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
    

    With these quick changes things should work the way you expect.

提交回复
热议问题