Rails activerecord의 모델에서 속성의 기본값을 어떻게 생성합니까? [복제]
이 질문에는 이미 답변이 있습니다.
- ActiveRecord에서 기본값을 어떻게 설정합니까? 답변 26 개
ActiveRecord에서 속성을 정의하여 속성의 기본값을 만들고 싶습니다. 기본적으로 레코드를 만들 때마다 attribute의 기본값을 원합니다 :status
. 나는 이것을 시도했다 :
class Task < ActiveRecord::Base
def status=(status)
status = 'P'
write_attribute(:status, status)
end
end
그러나 생성시 여전히 데이터베이스 에서이 오류를 검색합니다.
ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null
따라서 값이 속성에 적용되지 않은 것으로 가정합니다.
Rails에서이를 수행하는 우아한 방법은 무엇입니까?
많은 감사합니다.
마이그레이션에서 열의 기본 옵션을 설정할 수 있습니다
....
add_column :status, :string, :default => "P"
....
또는
콜백을 사용할 수 있습니다. before_save
class Task < ActiveRecord::Base
before_save :default_values
def default_values
self.status ||= 'P' # note self.status = 'P' if self.status.nil? might be safer (per @frontendbeauty)
end
end
얼마 전에이 문제가 발생했고 Rails 3.0의 옵션이 약간 다르기 때문에이 질문에 대한 또 다른 답변을 제공 할 것입니다.
Rails 3.0에서는 다음과 같이하고 싶습니다 :
class MyModel < ActiveRecord::Base
after_initialize :default_values
private
def default_values
self.name ||= "default value"
end
end
기본값이 필요한 경우 일반적으로 새 조치의보기가 렌더링되기 전에 새 레코드에 대해 기본값이 설정됩니다. 다음 방법은 양식을 렌더링 할 때 사용할 수 있도록 새 레코드에만 기본값을 설정합니다. before_save
그리고 before_create
너무 늦게 작동하지 않습니다 당신이 기본 값이 입력 필드에 표시하려는 경우 .
after_initialize do
if self.new_record?
# values will be available for new record forms.
self.status = 'P'
self.featured = true
end
end
코드를 전혀 쓰지 않고 할 수 있습니다. :) 데이터베이스의 열 기본값을 설정하기 만하면됩니다. 마이그레이션에서이 작업을 수행 할 수 있습니다. 예를 들면 다음과 같습니다.
create_table :projects do |t|
t.string :status, :null => false, :default => 'P'
...
t.timestamps
end
희망이 도움이됩니다.
해결책은 몇 가지에 달려 있습니다.
Is the default value dependent on other information available at creation time? Can you wipe the database with minimal consequences?
If you answered the first question yes, then you want to use Jim's solution
If you answered the second question yes, then you want to use Daniel's solution
If you answered no to both questions, you're probably better off adding and running a new migration.
class AddDefaultMigration < ActiveRecord::Migration
def self.up
change_column :tasks, :status, :string, :default => default_value, :null => false
end
end
:string can be replaced with any type that ActiveRecord::Migration recognizes.
CPU is cheap so the redefinition of Task in Jim's solution isn't going to cause many problems. Especially in a production environment. This migration is proper way of doing it as it is loaded it and called much less often.
I would consider using the attr_defaults found here. Your wildest dreams will come true.
Just strengthening Jim's answer
Using presence one can do
class Task < ActiveRecord::Base
before_save :default_values
def default_values
self.status = status.presence || 'P'
end
end
For column types Rails supports out of the box - like the string in this question - the best approach is to set the column default in the database itself as Daniel Kristensen indicates. Rails will introspect on the DB and initialize the object accordingly. Plus, that makes your DB safe from somebody adding a row outside of your Rails app and forgetting to initialize that column.
For column types Rails doesn't support out of the box - e.g. ENUM columns - Rails won't be able to introspect the column default. For these cases you do not want to use after_initialize (it is called every time an object is loaded from the DB as well as every time an object is created using .new), before_create (because it occurs after validation), or before_save (because it occurs upon update too, which is usually not what you want).
Rather, you want to set the attribute in a before_validation on: create, like so:
before_validation :set_status_because_rails_cannot, on: :create
def set_status_because_rails_cannot
self.status ||= 'P'
end
As I see it, there are two problems that need addressing when needing a default value.
- You need the value present when a new object is initialized. Using after_initialize is not suitable because, as stated, it will be called during calls to #find which will lead to a performance hit.
- You need to persist the default value when saved
Here is my solution:
# the reader providers a default if nil
# but this wont work when saved
def status
read_attribute(:status) || "P"
end
# so, define a before_validation callback
before_validation :set_defaults
protected
def set_defaults
# if a non-default status has been assigned, it will remain
# if no value has been assigned, the reader will return the default and assign it
# this keeps the default logic DRY
status = status
end
I'd love to know why people think of this approach.
I found a better way to do it now:
def status=(value)
self[:status] = 'P'
end
In Ruby a method call is allowed to have no parentheses, therefore I should name the local variable into something else, otherwise Ruby will recognize it as a method call.
'IT story' 카테고리의 다른 글
숫자에서 월 이름 가져 오기 (0) | 2020.05.13 |
---|---|
SSH 키 : " 'id_rsa.pub'에 대한 권한 0644가 너무 열려 있습니다." (0) | 2020.05.13 |
주석 핀에 맞게 MKMapView를 확대 하시겠습니까? (0) | 2020.05.13 |
데이터베이스 테이블에서 클래스 생성 (0) | 2020.05.13 |
Java에서 가장 자주 발생하는 동시성 문제는 무엇입니까? (0) | 2020.05.13 |