Вопрос по ruby-on-rails – Как инициализировать ActiveRecord со значениями в Rails?

24

На обычной Java я использую:

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

Однако я не смог найти простой стандартный способ сделать это в rails (3.2.3) с ActiveRecords.

1. override initialize
<code>def initialize(attributes = {}, options = {})
  @name  = attributes[:name]
  @email = f(attributes[:email])
  @admin = false
end
</code>

но это может быть упущено при созданиизапись из БД

2. using the after_initialize callback

переопределив это:

<code>def after_initialize(attributes = {}, options = {})
  ...
end
</code>

или с макросом:

<code>after_initialize : my_own_little_init
def my_own_little_init(attributes = {}, options = {})
  ...
end
</code>

но может бытьнекоторые проблемы с амортизацией.

Есть некоторыеДругой связив СО, но они могут быть устаревшими.

Так,what's the correct/standard method to use?

Вы уже можете сделать это без необходимости какого-либо специального кода:User.new(:name => 'Bon', :email => '[email protected]'). Вы хотите использовать его по-другому? Dylan Markow
или делать какие-то манипуляции с заданным входом, создавая Asaf
ты прав. Наверное, я спрашиваю о значениях по умолчанию, а не об значениях init, которые передаются при создании Asaf

Ваш Ответ

5   ответов
16

когда они будут применяться ко ВСЕМ записям. Та

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

Вот, каждое новое сообщение будет опубликовано как ложное. Если вы хотите использовать значения по умолчанию на уровне объекта, лучше всего использовать реализации в стиле Factory:

User.build_admin(params)

def self.build_admin(params)
  user = User.new(params)
  user.admin = true
  user
end
Благодарность. В общем, если я хочу иметь, например, нормализованные электронные письма во всех моих пользовательских экземплярах (при создании), я должен использоватьdef self.build_normalized(params) фабричный метод? это передает работу по поиску правильного метода создания клиенту моего кода. И это не охватывает все пути выполнения. Кроме того, есть ли заводская утилита для использования в рельсах? или стандартный шаблон? Asaf
И ... если мы поместим значения по умолчанию в определение схемы и любую другую логику инициализации в сам объект, разве это не распространяет одну проблему на разные части кода (и, возможно, уровни абстракций)? Asaf
@ Asaf - я бы использовал либо значения db init, либо заводской шаблон, а не оба. Jesse Wolgamott
14

After_initialize. Потому что при инициализации мы должны объявить супер, поэтому лучше использовать обратный вызов.

Ссылка не работает, этоafter_create новыйafter_intitialize? James McMahon
@ JamesMcMahon нет, у нас еще естьafter_intitialize. Я обновил ссылку документации. Mauro George
В последние годы я почти полностью избегал обратных вызовов AR. Для меня они усложняют тестирование, а мои модели - сложнее. Я хочу, чтобы мои модели были действительно глупыми. bennick
5

Одно из решений, которое мне нравится, - через прицелы:

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

Затем вы можете сделать и то и другое: создать нового пользователя в статусе администратора (т.е. сadmin ==true) с помощьюUser.admins.new(...) и таким же образом получи всех своих админовUser.admins.

Вы можете сделать несколько областей и использовать их в качестве шаблонов для создания / поиска. Также вы можете использоватьdefault_scope с тем же значением, но без имени, которое применяется по умолчанию.

Есть ли проблемы с использованиемdefault_scope для этого? а как насчет других манипуляций с параметрами в конструкторе? Asaf
Это полезно, если вы имеете дело, скажем, с моделью комментариев и хотите сохранить стертые комментарии для ФБР :) Просто установите default_scope какwhere(deleted: false) и вы никогда не столкнетесь с удаленными ответами, если не переопределите свою область действия, скажем, черComment.where(deleted: true) или черезunscoped метод:Comment.unscoped. Есть и другие способы, но мне нравится этот:) jdoe
Я немного знаком с областью видимости, но для поиска, а не для создания. тем не менее, я ищу способ правильно инициализировать мои объекты, а не "разбивать" их на области ... Asaf
anyways, я сразу начал с именованных областей поиска ... Asaf
default_scopes также чрезвычайно полезен для указания связанных записей, которые должны быть загружены вместе с текущей моделью. Это называется готовая загрузка, если вы не знакомы. Если вы обнаружите, что загружаете связанные модели снова и снова и просматриваете их циклически, вы можете значительно уменьшить попадания в БД следующим образом:default_scope include: :tags. Но это другая история. :) jdoe
4

ю в базе данных, очевидно, будет работать, похоже, он нарушает соглашение Rails о том, что приложением должна обрабатываться целостность данных (и, следовательно, значений по умолчанию?).

Я наткнулся на этопосл. Поскольку вы, возможно, не захотите сохранять запись в базе данных немедленно, я думаю, что лучший способ - переписать метод initialize с помощью вызоваwrite_attribute().

def initialize
  super
  write_attribute(name, "John Doe")
  write_attribute(email,  f(email))
  write_attribute(admin, false)
end
FYI На самом деле, after_create работал лучше для того, что мне было нужно, когда я использовал after_initialize, каждый раз, когда я делал .find для Модели с рандомизированным атрибутом, значение менялось, чего я не хотел concept47
Это не работает, потому что подпись метода неверна, просто нужно объявить необязательный параметр. Eduardo
по какой-то причине это вызывает проблемы, если вы попытаетесь сделать что-то вроде Model.new (param1: arg1, param2: arg2), вы получите ошибки «ArgumentError: неправильное количество аргументов (1 для 0)», похоже на ответ Мауро лучше лучше, если вы хотите динамически записывать атрибуты (например, рандомизированные ключи) concept47
Я согласен. Вы, вероятно, должны использовать after_initialize. clekstro
Я добавил пример необязательных параметров в следующем предложении ответа. Harry Fairbanks
4

Это будет работать в рельсах 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

Похожие вопросы