Estou tentando encontrar a melhor maneira de definir valores padrão para objetos no Rails.
O melhor que posso pensar é definir o valor padrão no new
método do controlador.
Alguém tem alguma opinião se isso é aceitável ou se existe uma maneira melhor de fazer isso?
ruby-on-rails
ruby
biagidp
fonte
fonte
Respostas:
"Correto" é uma palavra perigosa em Ruby. Geralmente, há mais de uma maneira de fazer qualquer coisa. Se você sabe que sempre desejará esse valor padrão para aquela coluna na tabela, configurá-los em um arquivo de migração de banco de dados é a maneira mais fácil:
Como o ActiveRecord descobre automaticamente suas propriedades de tabela e coluna, isso fará com que o mesmo padrão seja definido em qualquer modelo que o use em qualquer aplicativo Rails padrão.
No entanto, se você deseja apenas valores padrão definidos em casos específicos - digamos, é um modelo herdado que compartilha uma tabela com alguns outros - então outra maneira elegante é fazer isso diretamente em seu código Rails quando o objeto de modelo é criado:
Então, quando você fizer um
GenericPerson.new()
, o atributo "Doe" será sempre adicionado a, aPerson.new()
menos que você o substitua por outra coisa.fonte
.new
método de classe. A discussão daquela postagem do blog sobre a chamada direta do ActiveRecord.allocate
foi sobre objetos de modelo carregados com dados existentes do banco de dados. ( E é uma péssima ideia que o ActiveRecord funcione dessa forma, IMO. Mas isso nãochange_column_default :people, :last_name, nil
stackoverflow.com/a/1746246/483520change_column :people, :last_name, :string, default: "Doe"
Com base na resposta do SFEley, aqui está um atualizado / corrigido para as versões mais recentes do Rails:
fonte
change_column
pode ser bastante "estruturante", a operação reversa não pode ser deduzida. Se você não tiver certeza, teste executandodb:migrate
edb:rollback
logo após. Resposta aceita como o mesmo resultado, mas pelo menos é presumida!up
edown
como descrito acima de @GoBustoEm primeiro lugar, você não pode sobrecarregar,
initialize(*args)
pois não é chamado em todos os casos.Sua melhor opção é colocar seus padrões em sua migração:
A segunda melhor opção é colocar padrões em seu modelo, mas isso só funcionará com atributos que inicialmente são nulos. Você pode ter problemas como eu tive com as
boolean
colunas:Você precisa do
new_record?
para que os padrões não substituam os valores carregados do banco de dados.Você precisa
||=
impedir o Rails de sobrescrever os parâmetros passados no método de inicialização.fonte
after_initiation :your_method_name
.... 2 usoself.max_users ||= 10
after_initialize do
vez dedef after_initialize
Você também pode tentar
change_column_default
em suas migrações (testado no Rails 3.2.8):change_column_default API do Rails docs
fonte
Se estiver se referindo a objetos ActiveRecord, você tem (mais de) duas maneiras de fazer isso:
1. Use um: parâmetro padrão no banco de dados
POR EXEMPLO
Mais informações aqui: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
2. Use um retorno de chamada
POR EXEMPLO
before_validation_on_create
Mais informações aqui: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147
fonte
No Ruby on Rails v3.2.8, usando o
after_initialize
retorno de chamada ActiveRecord, você pode chamar um método em seu modelo que atribuirá os valores padrão para um novo objeto.Então, IMO, deve ser algo como:
Foo.bar = default_value
para esta instância, a menos que a instância contenhaattribute_whose_presence_has_been_validated
anteriormente em salvar / atualizar. Odefault_value
será então usado em conjunto com sua visualização para renderizar o formulário usando odefault_value
para obar
atributo.Na melhor das hipóteses, isso é hacky ...
EDITAR - usar 'new_record?' para verificar se instanciando de uma nova chamada
Em vez de verificar um valor de atributo, use o
new_record?
método integrado com trilhos. Portanto, o exemplo acima deve ser semelhante a:Isso é muito mais limpo. Ah, a magia do Rails - é mais inteligente do que eu.
fonte
after_initialize
retorno de chamada aqui? A documentação do Rails sobre callbacks tem exemplo de configuração do valor padrãobefore_create
sem verificações de condição extraSubscription
after_initialize
, em vez dobefore_create
retorno de chamada, é que queremos definir um valor padrão para o usuário (para uso em uma visualização) quando ele estiver criando novos objetos. Obefore_create
retorno de chamada é chamado após o usuário receber um novo objeto, fornecer sua entrada e enviar o objeto para criação ao controlador. O controlador então verifica se hábefore_create
retornos de chamada. Parece contra-intuitivo, mas é uma coisa de nomenclatura -before_create
refere-se àcreate
ação. Instanciar um novo objeto nãocreate
o faz.Para campos booleanos no Rails 3.2.6 pelo menos, isso funcionará em sua migração.
Colocar um
1
ou0
para um padrão não funcionará aqui, pois é um campo booleano. Deve ser um valortrue
oufalse
.fonte
Caso esteja lidando com um modelo, você pode usar a API de atributos no Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
basta adicionar uma migração com um nome de coluna adequado e, em seguida, no modelo configurá-la com:
fonte
Gerar uma migração e usar
change_column_default
, é sucinto e reversível:fonte
Se você estiver apenas definindo padrões para certos atributos de um modelo de banco de dados, consideraria usar valores de coluna padrão sql - você pode esclarecer quais tipos de padrões você está usando?
Existem várias abordagens para lidar com isso, este plugin parece uma opção interessante.
fonte
A sugestão para substituir new / initialize está provavelmente incompleta. O Rails (freqüentemente) chamará alocação para objetos ActiveRecord, e chamadas para alocar não resultarão em chamadas para inicializar.
Se você estiver falando sobre objetos ActiveRecord, dê uma olhada em substituir after_initialize.
Estas postagens do blog (não as minhas) são úteis:
Valores padrão Construtores padrão não chamados
[Edit: SFEley aponta que Rails realmente olha para o padrão no banco de dados quando instancia um novo objeto na memória - eu não tinha percebido isso.]
fonte
Eu precisava definir um padrão como se fosse especificado como valor de coluna padrão no banco de dados. Então se comporta assim
Como o retorno de chamada after_initialize é chamado depois de definir atributos de argumentos, não havia como saber se o atributo é nulo porque nunca foi definido ou porque foi intencionalmente definido como nulo. Então eu tive que fuçar um pouco e vim com esta solução simples.
Funciona muito bem para mim. (Rails 3.2.x)
fonte
Uma forma potencial ainda melhor / mais limpa do que as respostas propostas é sobrescrever o acessador, assim:
Consulte "Sobrescrevendo acessadores padrão" na documentação ActiveRecord :: Base e mais de StackOverflow sobre como usar self .
fonte
Eu respondi a uma pergunta semelhante aqui .. uma maneira limpa de fazer isso é usando Rails attr_accessor_with_default
ATUALIZAR
attr_accessor_with_default tornou-se obsoleto no Rails 3.2 .. você poderia fazer isso ao invés com Ruby puro
fonte
attr_accessor_with_default
está obsoleto a partir de rails> 3.1.0Se você está falando sobre objetos ActiveRecord, eu uso a gem 'attribute-defaults'.
Documentação e download: https://github.com/bsm/attribute-defaults
fonte
Você pode usar a gema rails_default_value. por exemplo:
https://github.com/keithrowell/rails_default_value
fonte
Você pode substituir o construtor do modelo ActiveRecord.
Como isso:
fonte