Ruby-on-rails 如何在 Rails 中设置默认值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1186400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:32:39  来源:igfitidea点击:

How to set default values in Rails?

ruby-on-railsruby

提问by biagidp

I'm trying to find the best way to set default values for objects in Rails.

我试图找到在 Rails 中为对象设置默认值的最佳方法。

The best I can think of is to set the default value in the newmethod in the controller.

我能想到的最好的new方法是在控制器中的方法中设置默认值。

Does anyone have any input if this is acceptable or if there's a better way to do it?

如果这是可以接受的或者是否有更好的方法来做到这一点,是否有人有任何意见?

采纳答案by SFEley

"Correct" is a dangerous word in Ruby. There's usually more than one way to do anything. If you know you'll alwayswant that default value for that column on that table, setting them in a DB migration file is the easiest way:

“正确”在 Ruby 中是一个危险的词。通常有不止一种方法可以做任何事情。如果您知道您将始终希望该表中该列的默认值,则在数据库迁移文件中设置它们是最简单的方法:

class SetDefault < ActiveRecord::Migration
  def self.up
    change_column :people, :last_name, :type, :default => "Doe"
  end

  def self.down
    # You can't currently remove default values in Rails
    raise ActiveRecord::IrreversibleMigration, "Can't remove the default"
  end
end

Because ActiveRecord autodiscovers your table and column properties, this will cause the same default to be set in any model using it in any standard Rails app.

由于 ActiveRecord 会自动发现您的表和列属性,这将导致在任何标准 Rails 应用程序中使用它的任何模型中设置相同的默认值。

However, if you only want default values set in specific cases -- say, it's an inherited model that shares a table with some others -- then another elegant way is do it directly in your Rails code when the model object is created:

但是,如果您只想在特定情况下设置默认值——比如说,它是一个与其他人共享一个表的继承模型——那么另一种优雅的方法是在创建模型对象时直接在 Rails 代码中执行此操作:

class GenericPerson < Person
  def initialize(attributes=nil)
    attr_with_defaults = {:last_name => "Doe"}.merge(attributes)
    super(attr_with_defaults)
  end
end

Then, when you do a GenericPerson.new(), it'll always trickle the "Doe" attribute up to Person.new()unless you override it with something else.

然后,当您执行 a 时GenericPerson.new()Person.new()除非您用其他内容覆盖它,否则它将始终将“Doe”属性涓涓细流。

回答by J-_-L

Based on SFEley's answer, here is an updated/fixed one for newer Rails versions:

根据 SFEley 的回答,这里是更新/修复的较新 Rails 版本:

class SetDefault < ActiveRecord::Migration
  def change
    change_column :table_name, :column_name, :type, default: "Your value"
  end
end

回答by Ian Purton

First of all you can't overload initialize(*args)as it's not called in all cases.

首先,您不能重载,initialize(*args)因为它并非在所有情况下都被调用。

Your best option is to put your defaults into your migration:

最好的选择是将默认值放入迁移中:

add_column :accounts, :max_users, :integer, :default => 10

Second best is to place defaults into your model but this will only work with attributes that are initially nil. You may have trouble as I did with booleancolumns:

其次是将默认值放入您的模型中,但这仅适用于最初为零的属性。您可能会遇到问题,就像我对boolean列所做的一样:

def after_initialize
  if new_record?
    max_users ||= 10
  end
end

You need the new_record?so the defaults don't override values loaded from the datbase.

您需要new_record?这样默认值不会覆盖从数据库加载的值。

You need ||=to stop Rails from overriding parameters passed into the initialize method.

您需要||=阻止 Rails 覆盖传递给 initialize 方法的参数。

回答by Sebastiaan Pouyet

You can also try change_column_defaultin your migrations (tested in Rails 3.2.8):

您还可以尝试change_column_default迁移(在 Rails 3.2.8 中测试):

class SetDefault < ActiveRecord::Migration
  def up
    # Set default value
    change_column_default :people, :last_name, "Smith"
  end

  def down
    # Remove default
    change_column_default :people, :last_name, nil
  end
end

change_column_default Rails API docs

change_column_default Rails API 文档

回答by Vlad Zloteanu

If you are referring to ActiveRecord objects, you have (more than) two ways of doing this:

如果您指的是 ActiveRecord 对象,则有(不止)两种方法可以做到这一点:

1. Use a :default parameter in the DB

1. 在数据库中使用 :default 参数

E.G.

例如

class AddSsl < ActiveRecord::Migration
  def self.up
    add_column :accounts, :ssl_enabled, :boolean, :default => true
  end

  def self.down
    remove_column :accounts, :ssl_enabled
  end
end

More info here: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

更多信息:http: //api.rubyonrails.org/classes/ActiveRecord/Migration.html

2. Use a callback

2. 使用回调

E.G. before_validation_on_create

例如 before_validation_on_create

More info here: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147

更多信息:http: //api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147

回答by erroric

In Ruby on Rails v3.2.8, using the after_initializeActiveRecord callback, you can call a method in your model that will assign the default values for a new object.

在 Ruby on Rails v3.2.8 中,使用after_initializeActiveRecord 回调,您可以调用模型中的方法,该方法将为新对象分配默认值。

after_initialize callback is triggered for each object that is found and instantiated by a finder, with after_initialize being triggered after new objects are instantiated as well (see ActiveRecord Callbacks).

after_initialize 回调为发现者找到并实例化的每个对象触发, after_initialize 在新对象实例化后触发(参见 ActiveRecord 回调)。

So, IMO it should look something like:

所以,IMO 应该是这样的:

class Foo < ActiveRecord::Base
  after_initialize :assign_defaults_on_new_Foo
  ...
  attr_accessible :bar
  ...
  private
  def assign_defaults_on_new_Foo
    # required to check an attribute for existence to weed out existing records
    self.bar = default_value unless self.attribute_whose_presence_has_been_validated
  end
end

Foo.bar = default_valuefor this instance unless the instance contains an attribute_whose_presence_has_been_validatedpreviously on save/update. The default_valuewill then be used in conjunction with your view to render the form using the default_valuefor the barattribute.

Foo.bar = default_value对于此实例,除非该实例包含attribute_whose_presence_has_been_validated以前的保存/更新。在default_value随后将在结合使用视图渲染使用形式default_valuebar属性。

At best this is hacky...

充其量这是hacky......

EDIT - use 'new_record?' to check if instantiating from a new call

编辑 - 使用“new_record?” 检查是否从新调用实例化

Instead of checking an attribute value, use the new_record?built-in method with rails. So, the above example should look like:

不要检查属性值,而是使用new_record?带有 rails的内置方法。所以,上面的例子应该是这样的:

class Foo < ActiveRecord::Base
  after_initialize :assign_defaults_on_new_Foo, if: 'new_record?'
  ...
  attr_accessible :bar
  ...
  private
  def assign_defaults_on_new_Foo
    self.bar = default_value
  end
end

This is much cleaner. Ah, the magic of Rails - it's smarter than me.

这样干净多了。啊,Rails 的魔力——它比我聪明。

回答by Silasj

For boolean fields in Rails 3.2.6 at least, this will work in your migration.

至少对于 Rails 3.2.6 中的布尔字段,这将适用于您的迁移。

def change
  add_column :users, :eula_accepted, :boolean, default: false
end

Putting a 1or 0for a default will not work here, since it is a boolean field. It must be a trueor falsevalue.

将 a10for设为默认值在这里不起作用,因为它是一个布尔字段。它必须是一个truefalse值。

回答by Paulo Fidalgo

In case you're dealing with a Model, you can use the Attriutes API in Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute

如果您正在处理模型,则可以使用 Rails 5+ 中的 Attriutes API http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute

just add a migration with a proper column name and then in the model set it with:

只需添加具有正确列名的迁移,然后在模型中将其设置为:

class StoreListing < ActiveRecord::Base
  attribute :country, :string, default: 'PT'
end

回答by Pere Joan Martorell

Generate a migration and use change_column_default, is succinct and reversible:

生成迁移和使用change_column_default,简洁且可逆:

class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
  def change
    change_column_default :people, :age, { from: nil, to: 0 }
  end
end

回答by Petr ''Bubák'' ?edivy

I needed to set a default just as if it was specified as default column value in DB. So it behaves like this

我需要设置一个默认值,就像它在 DB 中被指定为默认列值一样。所以它的行为是这样的

a = Item.new
a.published_at # => my default value

a = Item.new(:published_at => nil)
a.published_at # => nil

Because after_initialize callback is called after setting attributes from arguments, there was no way to know if the attribute is nil because it was never set or because it was intentionally set as nil. So I had to poke inside a bit and came with this simple solution.

因为 after_initialize 回调是在从参数设置属性后调用的,所以无法知道该属性是 nil 是因为它从未设置过还是因为它被有意设置为 nil。所以我不得不深入研究一下,并提出了这个简单的解决方案。

class Item < ActiveRecord::Base
  def self.column_defaults
    super.merge('published_at' => Time.now)
  end
end

Works great for me. (Rails 3.2.x)

对我很有用。(导轨 3.2.x)