VegaStudios
VegaStudios

Reputation: 324

Rails virtual attribute not available after save

I'm not sure if this is a problem within my app or my understanding of virtual attributes. Creating a Member object with a first_name and last_name virtual attribute works. However, when I go to retrieve the Member, the first and last name are nil. I say that it works because the User.invite! method it invokes successfully creates and saves a new User with the first and last name. My understanding is from this article below, but I wanted to get some insight whether I was missing or misunderstanding anything.

The Virtual Attribute is a class attribute, which has no representation in the database. It becomes available after object initialization and remains alive while the object itself is available (like the instance methods)

Member

class Member < ApplicationRecord
  belongs_to :store
  belongs_to :user

  attribute               :email, :string
  attribute               :first_name, :string
  attribute               :last_name, :string

  before_validation       :set_user_id, if: :email?

  private

    def set_user_id
      self.user = User.invite!({
        first_name: first_name,
        last_name: last_name,
        email: email
        })
    end
end

Console

Loading development environment (Rails 6.0.0)
irb(main):001:0> Member.last
  Member Load (0.5ms)  SELECT "members".* FROM "members" ORDER BY "members"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Member id: 55, store_id: 43, user_id: 3, created_at: "2019-09-03 02:05:27", updated_at: "2019-09-03 02:05:27", email: nil, first_name: nil, last_name: nil>

Upvotes: 1

Views: 650

Answers (2)

Vibol
Vibol

Reputation: 1168

I might go with this:

class Member < ApplicationRecord
  belongs_to :store
  belongs_to :user
end


class User < ApplicationRecord
  has_many :members
  has_many :stores, through: :members

  def self.invite_to_store(first_name, last_name, email, store_id)
    ActiveRecord::Base.transaction do
      user = invite!(first_name: first_name, last_name: last_name, email: email)
      user.members.create!(store_id: store_id)
    end
  end 
end

Then you can call User.invite_to_store('first name', 'last name', '[email protected]', 1)

Upvotes: 0

Maycon Seidel
Maycon Seidel

Reputation: 181

Actually, I didn't understand why you would like to use the attribute in this example. I believe that you want/should use delegate.

Basically, It seems to work when you invoke invite! because you probably are passing these attributes in parameters, so it initialize the object and set this "temporary variables". But, when you try to SELECT the register from database it's not there anymore.

As you flagged, remains alive while the object itself is available. Check that it says the object. When you do Member.last it initializes a new object with the data returned from database.

Upvotes: 1

Related Questions