实现用户技能方法的最佳方法 - Rails 4

时间:2014-12-12 09:44:51

标签: ruby-on-rails ruby-on-rails-4.1

所以我的问题或多或少如下。我有一个带有以下类的rails应用程序:

  • 用户
  • 技能

每个用户都可以拥有多种技能,并且可以从用户配置文件屏幕添加这些技能,这是用户控制器的显示操作。目前我已经设置了技能并且能够创建,但我无法在用户配置文件中添加预先构建的技能,我不确定是否需要在Users控制器中添加新操作或者我只需要使用来自技能控制器的更新操作。我的理想解决方案是管理员用户(已经创建并整理出来)继续用户配置文件并添加技能,但我完全不知道如何实现这一点。我的控制器,模型等如下:

skills_controller.rb

class SkillsController < ApplicationController
  before_action :set_skill, only: [:show, :edit, :update, :destroy]

  # GET /skills
  # GET /skills.json
  def index
    @skills = Skill.all
  end

  # GET /skills/1
  # GET /skills/1.json
  def show
  end

  # GET /skills/new
  def new
    @skill = Skill.new
  end

  # GET /skills/1/edit
  def edit
  end

  # POST /skills
  # POST /skills.json
  def create
    @skill = Skill.new(skill_params)
    user = User.find(params[:user_id])
    respond_to do |format|
      if @skill.save
        format.html { redirect_to @skill, notice: 'Skill was successfully created.' }
        format.json { render :show, status: :created, location: @skill }
      else
        format.html { render :new }
        format.json { render json: @skill.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /skills/1
  # PATCH/PUT /skills/1.json
  def update
    respond_to do |format|
      if @skill.update(skill_params)
        format.html { redirect_to @skill, notice: 'Skill was successfully updated.' }
        format.json { render :show, status: :ok, location: @skill }
      else
        format.html { render :edit }
        format.json { render json: @skill.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /skills/1
  # DELETE /skills/1.json
  def destroy
    @skill.destroy
    respond_to do |format|
      format.html { redirect_to skills_url, notice: 'Skill was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_skill
      @skill = Skill.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def skill_params
      params.require(:skill).permit(:name, :badge_url, :user_id)
    end
end

users_controller.rb

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update]
  before_action :correct_user,   only: [:edit, :update]

  def new
    @user = User.new
    @group_options = Group.all.map{|g| [ g.name, g.id] }
    @subunit_options = Subunit.all.map{|s| [ s.name, s.id] }
  end

  def index
    @users = User.paginate(page: params[:page]).order('created_at ASC')
  end

  def chf_index
    @chf = User.where(group_id: 1).paginate(page: params[:page]).order('created_at ASC')
  end

  def rmc_index
    @rmc = User.where(group_id: 2).paginate(page: params[:page]).order('created_at ASC')
  end

  def ra_index
    @ra = User.where(group_id: 3).paginate(page: params[:page]).order('created_at ASC')
  end

  def show
    @user = User.find(params[:id])
    @user_training_events = User.find(params[:id]).training_events.to_a
    @event_id = TrainingEvent.where(user_ids: @user.id).all
    @group = Group.find(@user.group_id)
    if @user.subunit_id.nil?
    else
      @subunit = Subunit.find(@user.subunit_id)
    end
    @current_user_id = current_user.id
    if @user.rank_id.nil?
    else
      @rank = Rank.find(@user.rank_id)
    end
  end

  def create
    @user = User.new(user_params)
    if @user.save
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end


  def edit
    @user = User.find(params[:id])
    @subunit_options = Subunit.all.map{|s| [ s.name, s.id] }
    @group_options = Group.all.map{|g| [ g.name, g.id] }
  end


  def update
    @user = User.find(params[:id])
    @subunit_options = Subunit.all.map{|s| [ s.name, s.id] }
    if @user.update(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

    # Decides which parameters can be passed to user creation
    def user_params
      params.require(:user).permit(:username, :email, :group_id, :subunit_id, :rank_id,     :training_event_id, :password, :password_confirmation)
    end

    # Confirms a logged-in user.
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

    # Confirms the correct user.
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user) || current_user.admin?
    end



end

skill.rb

class Skill < ActiveRecord::Base
    belongs_to :user
end

user.rb

class User < ActiveRecord::Base
    attr_accessor :remember_token, :activation_token, :reset_token
    before_save   :downcase_email
    before_create :create_activation_digest

    belongs_to :group
    has_many :ranks
    has_many :skills
    has_many :mission_notes
    has_and_belongs_to_many :training_events
    accepts_nested_attributes_for :skills

    validates :username, presence: true
    validates :email, presence: true
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
    validates :group_id, presence: true
    has_secure_password
    validates :password, length: { minimum: 6 }, allow_blank: true

    # Returns the hash digest of the given string.
    def User.digest(string)
        cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                      BCrypt::Engine.cost
        BCrypt::Password.create(string, cost: cost)
    end

    # Returns a random token.
    def User.new_token
        SecureRandom.urlsafe_base64
    end

    # Remembers a user in the database for use in persistent sessions.
    def remember
        self.remember_token = User.new_token
        update_attribute(:remember_digest, User.digest(remember_token))
    end

    # Returns true if the given token matches the digest.
    def authenticated?(remember_token)
        return false if remember_digest.nil?
        BCrypt::Password.new(remember_digest).is_password?(remember_token)
    end

    # Forgets a user.
    def forget
        update_attribute(:remember_digest, nil)
    end

    # Converts email to all lower-case.
    def downcase_email
      self.email = email.downcase
    end

    # Creates and assigns the activation token and digest.
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end

    # Returns true if the given token matches the digest.
    def authenticated?(attribute, token)
        digest = send("#{attribute}_digest")
        return false if digest.nil?
        BCrypt::Password.new(digest).is_password?(token)
    end

    # Activates an account.
      def activate
        update_attribute(:activated,    true)
        update_attribute(:activated_at, Time.zone.now)
      end

      # Sends activation email.
      def send_activation_email
        UserMailer.account_activation(self).deliver
      end

      # Sets the password reset attributes.
  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest,  User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  # Sends password reset email.
  def send_password_reset_email
    UserMailer.password_reset(self).deliver
  end

  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end


end

最后是routes.rb

Rails.application.routes.draw do

  resources :skills

  resources :subunits

  resources :mission_notes

  resources :training_events

  get 'password_resets/new'

  get 'password_resets/edit'

  root "categories#index"
  get 'static_pages/home'
  get 'help' => 'static_pages#help'
  get 'signup' => 'users#new'
  get    'login'   => 'sessions#new'
  post   'login'   => 'sessions#create'
  delete 'logout'  => 'sessions#destroy'

  get 'dynamic' => 'subunits#dynamic'

  get 'chf_index'  => 'users#chf_index'
  get 'rmc_index'  => 'users#rmc_index'
  get 'ra_index'  => 'users#ra_index'
  resources :categories, :has_many => :notes
  resources :notes
  resources :users do
    resources :skills
  end
  resources :ranks
  resources :groups

  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]

end

如果您需要其他信息,请告诉我

修改 添加以下作为我的函数定义

def add_skill_to_user
    user = User.find(params[:id])
    user.skills.create(skill_params) #skill name, level...
    @skills_options = Skill.all.map{|s| [ s.name, s.id] }
    #whatever happens when this is is done, redirect, json answer etc...
    if user.skills.update_all(skill_params)
      flash[:success] = "Skill Added"
    else
       render 'add_skill_to_user'
    end
  end

  private
    # Set skills params whitelist    
    def skill_params
      params.permit(:name, :user_id)
    end    

以及以下路线

post 'users/:id/add_skill_to_user' => 'users#add_skill_to_user'

这是我的表格

<%= form_tag({controller: "users", action: "add_skill_to_user"}, method: "put") do %>
    <%= collection_select(:skill, :name, Skill.all, :id, :name) %>
    <%= submit_tag 'Submit' %>
<%end%>

我现在无法提交带有技能名称和技能ID的表单,因为我收到此错误Empty list of attributes to change

1 个答案:

答案 0 :(得分:0)

您想要创建一个搜索用户的方法,然后添加技能。

def add_skill_to_user
  user = User.find(params[:user_id])
  user.skills.create(skill_params) #skill name, level...
  #whatever happens when this is is done, redirect, json answer etc...
end

然后创建路由,接受视图中的表单发送用户名和技能信息。

这应该足够了。

编辑:

根据表格:

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

form_tag({controller: "admin", action: "set_user_skill"}, method: "post(or put)") Then the form... and the submit button.
相关问题