Skip to content

Instantly share code, notes, and snippets.

@ccyrille
Last active April 5, 2019 12:23
Show Gist options
  • Save ccyrille/ba8c4e2e50c7e23f3873c9199ab7f38e to your computer and use it in GitHub Desktop.
Save ccyrille/ba8c4e2e50c7e23f3873c9199ab7f38e to your computer and use it in GitHub Desktop.
class User < ActiveRecord::Base
...
# << REMOVE ON NEXT RELEASE
def new_column
read_attribute(:new_column) if has_attribute?(:new_column)
end
def new_column=(value)
write_attribute(:new_column, value) if has_attribute?(:new_column)
end
# >> REMOVE ON NEXT RELEASE
...
end
@BuonOmo
Copy link

BuonOmo commented Jul 17, 2018

You could refactor this code quite a bit:

class User < ActiveRecord::Base
  # << REMOVE ON NEXT RELEASE
  attr_accessor(:new_column) unless column_names.include?("new_column")
  # >> REMOVE ON NEXT RELEASE
end

This will also allow you to use the usual rails method when the migration is already done, quite better than using read_attribute/write_attribute, which may have a different effect.

However, this would change the behavior written here. It would save the attribute per instance instead of ignoring when using User#new_column=. For instance:

# read/write_attribute version
user = User.new
user.new_column = 42
p user.new_column # => nil

# attr_accessor version
user = User.new
user.new_column = 42
p user.new_column # => 42

To keep the first behavior, you could write:

class User < ActiveRecord::Base
  # << REMOVE ON NEXT RELEASE
  unless column_names.include?("new_column")
    def new_column
      # eventually some default value
    end

    def new_column=(_value)
      # eventually some side effect, this will always return `_value` anyway
    end
  end
  # >> REMOVE ON NEXT RELEASE
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment