How to initialize an ActiveRecord with values in R

2020-02-10 11:45发布

In plain java I'd use:

public User(String name, String email) {
  this.name = name;
  this.email = f(email);
  this.admin = false;
}

However, I couldn't find a simple standard way to do in rails (3.2.3), with ActiveRecords.

1. override initialize

def initialize(attributes = {}, options = {})
  @name  = attributes[:name]
  @email = f(attributes[:email])
  @admin = false
end

but it might be missed when creating a record from the DB

2. using the after_initialize callback

by overriding it:

def after_initialize(attributes = {}, options = {})
  ...
end

or with the macro:

after_initialize : my_own_little_init
def my_own_little_init(attributes = {}, options = {})
  ...
end

but there may be some deprecation issues.

There are some other links in SO, but they may be out-of-date.


So, what's the correct/standard method to use?

5条回答
家丑人穷心不美
2楼-- · 2020-02-10 11:53

Your default values should be defined in your Schema when they will apply to ALL records. So

def change
  creates_table :posts do |t|
    t.boolean :published, default: false
    t.string :title
    t.text :content
    t.references :author
    t.timestamps
  end
end

Here, every new Post will have false for published. If you want default values at the object level, it's best to use Factory style implementations:

User.build_admin(params)

def self.build_admin(params)
  user = User.new(params)
  user.admin = true
  user
end
查看更多
疯言疯语
3楼-- · 2020-02-10 11:58

I was searching for something similar this morning. While setting a default value in the database will obviously work, it seems to break with Rails' convention of having data integrity (and therefore default values?) handled by the application.

I stumbled across this post. As you might not want to save the record to the database immediately, I think the best way is to overwrite the initialize method with a call to write_attribute().

def initialize
  super
  write_attribute(name, "John Doe")
  write_attribute(email,  f(email))
  write_attribute(admin, false)
end
查看更多
欢心
4楼-- · 2020-02-10 12:06

According to Rails Guides the best way to do this is with the after_initialize. Because with the initialize we have to declare the super, so it is best to use the callback.

查看更多
ゆ 、 Hurt°
5楼-- · 2020-02-10 12:08

This will work in rails 4.

def initialize(params)
    super
    params[:name] = params[:name] + "xyz" 
    write_attribute(:name, params[:name]) 
    write_attribute(:some_other_field, "stuff")
    write_attribute(:email, params[:email])
    write_attribute(:admin, false)
end
查看更多
\"骚年 ilove
6楼-- · 2020-02-10 12:13

One solution that I like is via scopes:

class User ...
   scope :admins, where(admin: true)

Then you can do both: create new User in the admin status(i.e. with admin==true) via User.admins.new(...) and also fetch all your admins in the same way User.admins.

You can make few scopes and use few of them as templates for creating/searching. Also you can use default_scope with the same meaning, but without a name as it is applied by default.

查看更多
登录 后发表回答