繁体   English   中英

活动记录验证,存在不起作用

[英]Active Record Validations, presence of not working

我正在处理一个表单,用于为Ruby on Rails项目创建新用户。 我首先要提到的是,正确填写表单并以正确的方式创建用户时,表单本身可以正常工作。 但是,并非所有的Active Record Validation都在起作用,尤其是validates :institution_pid, presence: true位。 表单的其余部分按应有的方式工作。 如果元素为空白或正确填写,屏幕上会弹出一条错误消息,用户可以对其进行修复,并且表单不会提交。 但是,如果表单是在未选择机构的情况下提交的,那么无论如何它都不会显示该错误,而是无论如何都会提交该错误:

ActiveFedora::ObjectNotFoundError in UsersController#create

显然,这是在发生,因为它正在尝试使用尚未填写的表格使用该机构。 我不知道为什么要这样做,然后提交,而不是因为表单未正确填写而使验证弹出错误。

这是我的用户模型:

class User < ActiveRecord::Base
  # Connects this user object to Hydra behaviors. 
  include Hydra::User

  # Connects this user object to Blacklights Bookmarks. 
  include Blacklight::User
  include Aptrust::SolrHelper

  # Connects this user object to Role-management behaviors. 
  include Hydra::RoleManagement::UserRoles

  # Include default devise modules. Others available are:
  # :database_authenticatable,
  # :recoverable, :rememberable, :trackable, :validatable,
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :timeoutable,     :validatable

  validates :email, :phone_number, :role_ids, presence: true
  validates :email, uniqueness: true
  validates :institution_pid, presence: true
  validate :institution_pid_points_at_institution

  # Custom format validations.  See app/validators
  validates :name, person_name_format: true, if: ->{ name.present? }
  validates :email, email: true

  # Handle and normalize phone numbers
  phony_normalize :phone_number, :default_country_code => 'US'

  validates :phone_number, :phony_plausible => true

  # This method assigns permission groups
  def groups
    super + institution_groups
  end

  def institution_groups
    if institutional_admin?
      ["Admin_At_#{institution_group_suffix}"]
    elsif institutional_user?
      ["User_At_#{institution_group_suffix}"]
    else
      []
    end
  end

  # Blacklight uses #to_s on youruser class to get a user-displayable 
  # login/identifier for the account. 
  #
  # Method modified from the Blacklight default.
  def to_s
    name || email
  end

  def as_json(options = nil)
    json_data = super
    json_data.delete('api_secret_key')
    json_data.delete('encrypted_api_secret_key')
    json_data
  end

  # Roles are managed through the hydra-role-management gem.
  def is?(role)
    self.roles.pluck(:name).include?(role.to_s)
  end

  def admin?
    is? 'admin'
  end

  def institutional_admin?
    is? 'institutional_admin'
  end

  def institutional_user?
    is? 'institutional_user'
  end

  def role_id
    if(admin?)
      Role.where(name: 'admin').first_or_create.id
    elsif(institutional_admin?)
      Role.where(name: 'institutional_admin').first_or_create.id
    elsif(institutional_user?)
      Role.where(name: 'institutional_user').first_or_create.id
    end
  end

  # Since an Institution is an ActiveFedora Object, these two objects cannot be related as normal (i.e. belongs_to)
  # They will be connected through the User.institution_pid.
  def institution
    @institution ||= Institution.find(self.institution_pid)
  rescue ActiveFedora::ObjectNotFoundError => e
    logger.warn "#{self.institution_pid} is set as the institution for #{self}, but it doesn't exist"
    @institution = NilInstitution.new
  end

  def institution_group_suffix
    clean_for_solr(institution_pid)
  end

  # Guest users are disabled in this application.  The default Blacklight installation includes the gem devise-guests
  # which is not bundled with this app.  hydra-role-management gem requires a guest boolean, so we must provide it here.
  # This will be fixed in hydra-role-management 0.1.1
  def guest?
    false
  end

  attr_reader :api_secret_key

  def api_secret_key=(key)
    @api_secret_key = key
    self.encrypted_api_secret_key = if key.blank?
      nil
    else
       password_digest(key)
    end
  end

  # Generate a new API key for this user
  def generate_api_key(length = 20)
    self.api_secret_key = SecureRandom.hex(length)
  end

  # Verifies whether an API key (from sign in) matches the user's API key.
  def valid_api_key?(input_key)
    return false if encrypted_api_secret_key.blank?
    bcrypt  = ::BCrypt::Password.new(encrypted_api_secret_key)
    key = ::BCrypt::Engine.hash_secret("#{input_key}#{User.pepper}", bcrypt.salt)
    Devise.secure_compare(key, encrypted_api_secret_key)
  end

  class NilInstitution
    def name
      "Deleted Institution"
    end

    def to_param
      'deleted'
    end

    def brief_name
      "Deleted Institution"
    end

    def users
      []
    end

    def intellectual_objects
      []
    end

    def bytes_by_format
      {}
    end
  end

  private

  def institution_pid_points_at_institution
    errors.add(:institution_pid, "is not a valid institution") unless Institution.exists?(institution_pid)
  end

end

这是我的用户控制器:

class UsersController < ApplicationController
  inherit_resources
  load_and_authorize_resource
  before_filter :authenticate_user!

  def destroy
    name = @user.to_s
    destroy!(notice: "User #{@user.to_s} was deleted.")
  end

  def edit_password
    @user = current_user
  end

  def update_password
    @user = User.find(current_user.id)
    if @user.update_with_password(user_params)
      sign_in @user, :bypass => true
      redirect_to root_path
      flash[:notice] = "Successfully changed password."
    else
      redirect_to root_path
      flash[:alert] = "Current password was incorrect, new password was too short, or passwords did not match. Password has not been changed."
    end
  end

  def generate_api_key
    @user.generate_api_key

    if @user.save
      msg = ["Please record this key.  If you lose it, you will have to generate a new key.",
         "Your API secret key is: #{@user.api_secret_key}"]
      msg = msg.join("<br/>").html_safe
      flash[:notice] = msg
    else
      flash[:alert] = 'ERROR: Unable to create API key.'
    end

    redirect_to user_path(@user)
  end

  private

    def build_resource_params
      [params.fetch(:user, {}).permit(:name, :email, :phone_number, :password, :password_confirmation).tap do |p|
        p[:institution_pid] = build_institution_pid if params[:user][:institution_pid]
        p[:role_ids] = build_role_ids if params[:user][:role_ids]
      end]
    end

    def build_institution_pid
      institution = Institution.find(params[:user][:institution_pid])
      authorize!(:add_user, institution)
      institution.id
    end

    def build_role_ids
      [].tap do |role_ids|
        unless params[:user][:role_ids].empty?
          roles = Role.find(params[:user][:role_ids])

            authorize!(:add_user, roles)
            role_ids << roles.id

        end
      end
    end

  def user_params
    params.required(:user).permit(:password, :password_confirmation, :current_password)
  end

end

这是我正在使用的表单的代码:

<div class="page-header">
  <h1>Registering New User</h1>
</div>

<%= simple_form_for(@user, html: {class: 'form-horizontal'}) do |f| %>
    <%= f.error_notification %>

    <div class="form-inputs">
      <%= f.input :name, autofocus: true %>
      <%= f.input :email %>
      <%= f.input :phone_number %>

      <%= f.input :institution_pid, collection: institutions_for_select, as: :select, label: "Institution" %>

      <%= f.association :roles, collection: roles_for_select, as: :radio_buttons %>

      <%= f.input :password %>
      <%= f.input :password_confirmation %>

    </div>
    <br>
    <div class="form-actions">
      <%= button_tag(type: 'submit', class: "btn doc-action-btn btn-success") do %>
          <i class="glyphicon glyphicon-check"></i> Submit
      <% end %>
      <%= link_to @user, {class: "btn doc-action-btn btn-cancel"} do %>
          <i class="glyphicon glyphicon-remove"></i> Cancel
      <% end %>
    </div>
<% end %>

这是由机构元素的表单生成的HTML,如果有帮助,它会给我带来麻烦。

<div class="controls">
  <select class="select required" id="user_institution_pid" name="user[institution_pid]">
    <option value=""></option>  
    <option value="aptrust-dev:363">APTrust</option>
    <option selected="selected" value="aptrust-dev:365">North Carolina State University</option>
    <option value="aptrust-dev:364">Columbia University</option>
  </select>
</div>

日志:

Started POST "/users" for 127.0.0.1 at 2014-02-28 09:05:15 -0500
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓",    "authenticity_token"=>"WjALLu82iJDDNBEnNpdqupVERdYVOg1l1W/t5v7yaog=", "user"=>{"name"=>"", "email"=>"", "phone_number"=>"", "institution_pid"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}
Unpermitted parameters: institution_pid
Completed 500 Internal Server Error in 3ms

ActiveFedora::ObjectNotFoundError (Unable to find "" in fedora. ):
  app/controllers/users_controller.rb:52:in `build_institution_pid'
  app/controllers/users_controller.rb:46:in `block in build_resource_params'
  app/controllers/users_controller.rb:45:in `tap'
  app/controllers/users_controller.rb:45:in `build_resource_params'


  Rendered /Users/kec6en/.rvm/gems/ruby-2.0.0-p353@fluctus/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.7ms)
  Rendered /Users/kec6en/.rvm/gems/ruby-2.0.0-p353@fluctus/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
  Rendered /Users/kec6en/.rvm/gems/ruby-2.0.0-p353@fluctus/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms)
  Rendered /Users/kec6en/.rvm/gems/ruby-2.0.0-p353@fluctus/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (22.0ms)

这就是使您的代码失败的原因。

Unpermitted parameters: institution_pid

params.require(:user).permit(:institution_pid)

或某物 像这样。

查看更多http://edgeapi.rubyonrails.org/classes/ActionController/Parameters.html

我想到了。 仍然感谢您查看我的代码。 我需要添加一行以检查build_institution_pid方法中的参数是否为空。 现在,一切都验证了应有的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM