Кажется, не удается вытащить атрибуты этого объекта

#ruby-on-rails #intellij-idea #rubymine

Вопрос:

У меня есть метод, в котором вызывается объект, но я, похоже, не могу вытащить атрибуты этого объекта, и я не понимаю, почему.

     def set_cashier
      test = User.first
      result = test.login
      Rails.logger.debug "User is: #{result}"
 

когда я устанавливаю точку останова во второй строке в среде разработки rubymine (я вижу следующее)

     def set_cashier
      test = User.first   test: #<User:0x00000004809ea0>
      result = test.login    result: nil  test: #<User:0x00000004809ea0>
      Rails.logger.debug "User is: #{result}"

 

Я знаю, что у меня есть атрибуты этого объекта, такие как id и login . Когда я запускаю отладчик в своей среде разработки, я вижу @attributes = Hash(17 elements) , и я вижу, что они перечислены внутри как 'id' = "433" и 'login' = "firstname.lastname" etc…in отладчик rubymine выглядит примерно так…

 result = nil
test = {User}#<User:0x00000004809ea0>
    @attributes = Hash(17 elements)
       'id' = "433"
       'login' = "firstname.lastname"
      ...
 

Как мне вернуть значение «вход»?

тест = Пользователь.сначала, кажется, появляется объект, который я вижу на вкладке Переменные отладчика, который я могу открыть и увидеть значение «@атрибуты = Хэш(17 элементов)», и я вижу эти значения внутри….и все же…

«результат = test.login» дает нулевой результат, который так сбивает с толку

Я бы подумал, что «test = User.first.login» должен работать …

     def set_cashier
      test = User.first.login
      result = test
      Rails.logger.debug "User.first is: #{result}"
 

но это дает ту же ошибку …так запутанно.

(полная ошибка, отображаемая в браузере, выглядит так…)

 You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
 

I’ve been at this for a few days now. If this question does not make sense please let me know.

Thank you for your time.


UPDATED:

Per request of a commenter I’m including the code for the User model
(By the way…I inherited this code…so nothing in this file was written by me)

Note:
Rails 3.1 (updated from a rails 2.x app)
ruby 1.9.3p551

user.rb

 class User < ActiveRecord::Base
  acts_as_userstamp
  has_and_belongs_to_many "roles"

  # Virtual attribute for the unencrypted password
  attr_accessor :password

  validates_presence_of     :login, :email
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?, :allow_nil => true
  validates_confirmation_of :password,                   :if => :password_required?
  validates_length_of       :login,    :within => 3..40, :allow_nil => true
  validates_length_of       :email,    :within => 3..100, :allow_nil => true
  validates_uniqueness_of   :login, :email, :case_sensitive => false
  validates_uniqueness_of   :cashier_code, :if => :cashier_code
  validates_format_of       :login, :with => /[^0-9]/, :message => "must contain a non-numeric character"
  before_save :encrypt_password
  before_save :add_cashier_code
  before_save :disable_reason_cannot_login_on_reenable

  def disable_reason_cannot_login_on_reenable
    return unless self.can_login amp;amp; self.can_login_changed?
    self.reason_cannot_login = "" if self.reason_cannot_login amp;amp; self.reason_cannot_login.length > 0
  end

  belongs_to :contact
  has_one :skedjulnator_access

  ####################################################
  # I HAVE NO IDEA WHAT THIS IS HERE FOR, BUT IF YOU #
  # FORGET ABOUT IT YOU WILL SPEND AN HOUR TRYING TO #
  # FIGURE OUT WHAT YOU DID WRONG                    #
  ####################################################
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :password, :password_confirmation, :can_login, :shared

  scope :can_login, {:conditions => ["can_login = 't'"]}

  def self.hidden_columns
    super   [:crypted_password, :salt]
  end

  def can_view_disciplinary_information?
    !! (self.contact and self.contact.worker and self.contact.worker.worker_type_today and self.contact.worker.worker_type_today.name != 'inactive')
  end

  def update_skedjulnator_access_time
    self.skedjulnator_access ||= SkedjulnatorAccess.new
    self.skedjulnator_access.user_id_will_change!
    self.skedjulnator_access.save!
  end

  def grantable_roles
    self.roles.include?(Role.find_by_name('ADMIN')) ? Role.find(:all) : self.roles
  end

  def to_s
    login
  end

  def self.reset_all_cashier_codes
    self.find(:all).each{|x|
      x.reset_cashier_code
      x.save
    }
  end

  def contact_display_name
    self.contact ? self.contact.display_name : self.login
  end

  def add_cashier_code
    reset_cashier_code if !self.shared and cashier_code.nil?
  end

  def reset_cashier_code
    valid_codes = (1000..9999).to_a - User.find(:all).collect{|x| x.cashier_code}
    my_code = valid_codes[rand(valid_codes.length)]
    self.cashier_code = my_code
  end

  def merge_in(other)
    for i in [:actions, :donations, :sales, :types, :users, :volunteer_tasks, :contacts, :gizmo_returns]
      User.connection.execute("UPDATE #{i.to_s} SET created_by = #{self.id} WHERE created_by = #{other.id}")
      User.connection.execute("UPDATE #{i.to_s} SET updated_by = #{self.id} WHERE updated_by = #{other.id}")
    end
    ["donations", "sales", "volunteer_tasks", "disbursements", "recyclings", "contacts"].each{|x|
      User.connection.execute("UPDATE #{x.to_s} SET cashier_created_by = #{self.id} WHERE cashier_created_by = #{other.id}")
      User.connection.execute("UPDATE #{x.to_s} SET cashier_updated_by = #{self.id} WHERE cashier_updated_by = #{other.id}")
    }
    self.roles = (self.roles   other.roles).uniq
    self.save!
  end

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    if login.to_i.to_s == login
      u = find_by_contact_id(login.to_i)
    else
      u = find_by_login(login) # need to get the salt
    end
    return u if u amp;amp; u.can_login amp;amp; u.authenticated?(password)
    return nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at amp;amp; Time.now.utc < remember_token_expires_at
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

  def remember_me_for(time)
    remember_me_until time.from_now.utc
  end

  def remember_me_until(time)
    self.remember_token_expires_at = time
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end

  # start auth junk

  def User.current_user
    Thread.current['user'] || User.fake_new
  end

  attr_accessor :fake_logged_in

  def User.fake_new
    u = User.new
    u.fake_logged_in = true
    u
  end

  def logged_in
    ! fake_logged_in
  end

  def to_privileges
    return "logged_in" if self.logged_in
  end

  def privileges
    @privileges ||= _privileges
  end

  def _privileges
    olda = []
    return olda if !self.can_login
    a = [self, self.contact, self.contact ? self.contact.worker : nil, self.roles].flatten.select{|x| !x.nil?}.map{|x| x.to_privileges}.flatten.select{|x| !x.nil?}.map{|x| Privilege.by_name(x)}
    while olda != a
      a = a.select{|x| !x.restrict} if self.shared
      olda = a.dup
      a << olda.map{|x| x.children}.flatten
      a = a.flatten.sort_by(amp;:name).uniq
      a = a.select{|x| !x.restrict} if self.shared
    end
    a = a.map{|x| x.name}
    a
  end

  def has_privileges(*privs)
    positive_privs = []
    negative_privs = []
    privs.flatten!
    for i in privs
      if i.match(/^!/)
        negative_privs << i.sub(/^!/, "")
      else
        positive_privs << i
      end
    end
    if positive_privs.length > 0
      positive_privs << "role_admin"
    end
    if negative_privs.length > 0
      negative_privs << "role_admin"
    end
    my_privs = self.privileges
    #puts "NEG: #{negative_privs.inspect}, POS: #{positive_privs.inspect}, MY: #{my_privs.inspect}"
    return (negative_privs amp; my_privs).length == 0 amp;amp; ((positive_privs amp; my_privs).length > 0 || positive_privs.length == 0)
  end

  # end auth junk

  protected
  # before filter
  def encrypt_password
    return if password.blank?
    self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
    self.crypted_password = encrypt(password)
  end

  def password_required?
    crypted_password.blank? || !password.blank?
  end

end

 

Устранение IDE как источника проблем:

Поэтому я запустил консоль Rails и получил следующую ошибку…

 irb(main):001:0> User.first
  User Load (0.5ms)  SELECT "users".* FROM "users" LIMIT 1
   (0.1ms)  SHOW search_path
  User Indexes (1.1ms)   SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
 FROM pg_class t
 INNER JOIN pg_index d ON t.oid = d.indrelid
 INNER JOIN pg_class i ON d.indexrelid = i.oid
 WHERE i.relkind = 'i'
 AND d.indisprimary = 'f'
 AND t.relname = 'users'
 AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('"$user"','public') )
 ORDER BY i.relname

  User Indexes (0.4ms)   SELECT c2.relname, i.indisunique, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)
 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
 WHERE c.relname = 'users'
 AND c.oid = i.indrelid AND i.indexrelid = c2.oid
 AND i.indisprimary = 'f'
 AND i.indexprs IS NOT NULL
 ORDER BY 1

(Object doesn't support #inspect)
=>
irb(main):002:0>
 

…очень запутанно

Комментарии:

1. Можете ли вы добавить определение User в свой вопрос? Вы получаете ту же ошибку для какого-либо атрибута или просто login ? Я думаю, что еще одна вещь, которую нужно попробовать, — это запустить rails console и посмотреть, есть ли у вас та же проблема (т. Е. Исключить проблему с вашей IDE).

2. является User ли модель Rails моделью? он был сохранен в БД перед запуском set_cashier ?

3. @rmlockerd обновил мой пост кодом для модели пользователя. Да, та же ошибка для любых других атрибутов. Также запустил user.first в консоли rails…опубликовал вывод в разделе «обновлено» в посте.

4. Ваша проблема почти наверняка заключается в том, что модель определяет attr_accessors поверх ваших атрибутов ActiveRecord. Я не думаю, что когда-либо использовал Rails 2, так что, возможно, это что-то сделало в тот день, но в более поздних версиях Rails это создаст метод, который возвращает значение переменной экземпляра @login (или что-то еще), а не фактический атрибут базы данных. Прокомментируйте эту строчку и посмотрите, как вы пойдете.

5. @rmlockerd хм, так что поместите строку 6 attr_accessor :password ниже…скажем… строка 37 attr_accessible :login, :email, :password, :password_confirmation, :can_login, :shared ?