Rails에서 기본값을 설정하는 방법은 무엇입니까?


108

Rails에서 객체의 기본값을 설정하는 가장 좋은 방법을 찾으려고합니다.

내가 생각할 수있는 최선의 new방법은 컨트롤러 의 메서드에서 기본값을 설정하는 것입니다 .

이것이 수용 가능하거나 더 나은 방법이 있다면 누구든지 의견을 가지고 있습니까?


1
이 개체는 무엇입니까? 그들은 어떻게 소비 / 사용됩니까? 뷰를 렌더링하는 동안 또는 컨트롤러 로직에 사용됩니까?
Gishu

3
ActiveRecord 개체에 대해 이야기하고 있다면 '기본값'문제에 대한 올바른 해결책이 없다고 말해야합니다. 만 미친 해킹 및 레일 저자는이 기능이 가치가 있다고 생각하지 않는 것 (단지는 지역 사회가 레일로 놀라운 ..)
마우

허용되고 대부분의 답변은 ActiveRecords에 초점을 맞추기 때문에 원래 질문은 AcitveRecords에 관한 것이라고 가정합니다. 의 따라서 가능한 중복 stackoverflow.com/questions/328525/...
치로 틸리郝海东冠状病六四事件法轮功

답변:


98

"정답"은 Ruby에서 위험한 단어입니다. 일반적으로 하나 이상의 방법이 있습니다. 해당 테이블의 해당 열에 대해 항상 기본값을 원한다는 것을 알고 있다면 DB 마이그레이션 파일에서 설정하는 것이 가장 쉬운 방법입니다.

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

ActiveRecord는 테이블 및 열 속성을 자동 검색하기 때문에 표준 Rails 앱에서 사용하는 모든 모델에서 동일한 기본값이 설정됩니다.

그러나 특정 경우에만 기본값을 설정하려는 경우 (예 : 다른 테이블과 테이블을 공유하는 상속 된 모델) 다른 우아한 방법은 모델 객체가 생성 될 때 Rails 코드에서 직접 수행하는 것입니다.

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

그런 다음을 수행 할 때 다른 항목으로 재정의하지 않는 한 GenericPerson.new()항상 "Doe"속성을 조금씩 떨어 뜨 Person.new()립니다.


2
시도 해봐. .new클래스 메서드로 호출 된 새 모델 객체에서 작동합니다 . ActiveRecord 직접 호출 .allocate에 대한 블로그 게시물의 토론은 데이터베이스에서 기존 데이터로로드 된 모델 객체에 대한 것이 었습니다. ( 그리고 이 일에 액티브에 대한 끔찍한 생각이 그런 식으로, IMO 그러나 그 점 옆의..)
SFEley

2
뒤로 물러서서 원래 포스터의 질문 인 Nikita를 읽고 내 의견을 순서대로 읽으면 더 이해가 될 것입니다. 그렇지 않다면 ... 글쎄요, 질문에 대한 답을 얻었습니다. 좋은 하루 되세요.
SFEley 2011 년

8
다운 마이그레이션에 더 적합 : change_column_default :people, :last_name, nil stackoverflow.com/a/1746246/483520
Nolan Amy

9
최신 레일 버전의 경우 기본 매개 변수 앞에 추가 유형 매개 변수가 필요합니다. 이 페이지에서 : type을 검색하십시오.
Ben Wheeler

3
@JoelBrewer 오늘이 문제를 만났습니다. Rails 4의 경우 열 유형도 지정해야합니다.change_column :people, :last_name, :string, default: "Doe"
GoBusto

56

SFEley의 답변을 기반으로 다음은 최신 Rails 버전에 대한 업데이트 / 수정 된 것입니다.

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

2
Rails 4.2.x에서는 작동하지 않습니다 (이후 버전에서는 테스트되지 않음). 로 change_column매우 "구조"가 될 수 있으며, 역 동작을 추론 할 수 없습니다. 확실하지 않은 경우에, 다만 실행하여 테스트 db:migratedb:rollback직후. 동일한 결과로 받아 들인 대답이지만 적어도 가정합니다!
gfd

1
이것은 레일 5.1에서 작동하지만 당신이해야 할 것입니다 .. 나에게 정답 updown@GoBusto에서 설명한 것처럼
파브리 지오 Bertoglio

22

우선 initialize(*args)모든 경우에 호출 되지 않으므로 오버로드 할 수 없습니다 .

가장 좋은 방법은 기본값을 마이그레이션에 적용하는 것입니다.

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

두 번째로 좋은 방법은 기본값을 모델에 배치하는 것이지만 처음에는 nil 인 속성에서만 작동합니다. boolean열에서 했던 것처럼 문제가있을 수 있습니다 .

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

new_record?기본값이 데이터베이스에서로드 된 값을 재정의하지 않도록하기 위해 필요합니다 .

||=Rails가 initialize 메소드에 전달 된 매개 변수를 재정의하지 못하도록 해야 합니다.


12
사소한 참고 사항-두 가지 작업을 원합니다 ..... 1) after_initialize 메서드를 호출하지 마십시오. 당신이 원하는 after_initiation :your_method_name.... 2 사용self.max_users ||= 10
Jesse Wolgamott

5
부울의 경우 다음과 같이하십시오. prop = true if prop.nil?
Francis Potter

2
또는 after_initialize do대신def after_initialize
fotanus

self.max_users는 안전합니다.
Ken Ratanachai S.

15

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 문서


1
수락 된 답변이 더 완전하지만이 깔끔하고 문서화 된 답변이 마음에 듭니다 ... 감사합니다!
gfd

7

ActiveRecord 객체를 참조하는 경우 다음 두 가지 방법이 있습니다.

1. DB에서 : default 매개 변수 사용

EG

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

자세한 정보 : http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

2. 콜백 사용

EG before_validation_on_create

자세한 정보 : http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147


2
객체가 저장 될 때까지 설정되지 않는 데이터베이스에서 기본값을 사용하는 데 문제가 있지 않습니까? 기본값이 채워진 새 개체를 생성하려면 이니셜 라이저에서 설정해야합니다.
Rafe

부울은 기본적으로 1 또는 0으로 설정할 수 없습니다. true 또는 false로 설정해야합니다 (Silasj의 답변 참조).
Jamon Holmgren 2012

발언에 대한 감사를 @JamonHolmgren, 나는 대답 : 수정
블라드 Zloteanu

어떤 문제 @VladZloteanu 없습니다
잼 그렌

7

Ruby on Rails v3.2.8에서는 after_initializeActiveRecord 콜백을 사용하여 새 개체에 대한 기본값을 할당하는 모델의 메서드를 호출 할 수 있습니다.

after_initialize 콜백은 파인더에 의해 발견되고 인스턴스화 된 각 객체에 대해 트리거되며, after_initialize는 새 객체가 인스턴스화 된 후에도 트리거됩니다 ( ActiveRecord 콜백 참조 ).

따라서 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_value인스턴스에 attribute_whose_presence_has_been_validated이전 저장 / 업데이트 가 포함되어 있지 않은 경우이 인스턴스의 경우 . 는 default_value다음을 사용하여 폼 렌더링 할 뷰와 함께 사용됩니다 default_value에 대한 bar속성을.

기껏해야 해키입니다 ...

편집- 'new_record?'사용 새 호출에서 인스턴스화하는지 확인하려면

속성 값을 확인하는 대신 new_record? 레일과 함께 기본 제공 방법을 . 따라서 위의 예는 다음과 같습니다.

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

이것은 훨씬 더 깨끗합니다. 아, Rails의 마법-나보다 똑똑합니다.


이것은 예상대로 작동하지 않습니다. new에 기본값 만 설정해야했지만 발견되고 인스턴스화되는 각 개체에 대한 속성 (즉, db에서로드 된 레코드)에 대한 기본값도 설정합니다. 기본값을 할당하기 전에 값을 찾기 위해 객체 속성을 검사 할 수 있지만 이는 매우 우아하거나 강력한 솔루션이 아닙니다.
오류

1
after_initialize여기서 콜백 을 추천하는 이유는 무엇 입니까? 콜백에 대한 Rails 문서에는 before_create추가 조건 검사없이 기본값을 설정하는 예제 가 있습니다
Dfr

@Dfr-나는 그것을 놓친 것이 틀림 없다, 당신은 나에게 검토를위한 링크를 던질 수 있고 나는 대답을 업데이트 할 것이다 ...
오류가있는

예, 여기 api.rubyonrails.org/classes/ActiveRecord/Callbacks.html 첫 번째 예제, 클래스Subscription
Dfr

5
@Dfr - 우리가 사용하고 있는지 그 이유 after_initialize대신에, before_create콜백, 우리가에 대한 기본 값을 설정하려는 것입니다 사용자 가 새로운 객체를 생성 할 때 (뷰에 사용). before_create콜백이 호출 사용자가 새로운 객체를 제공하고있다, 자신의 입력을 제공하고, 컨트롤러에 창조를 위해 개체를 제출했다. 그런 다음 컨트롤러는 before_create콜백 을 확인합니다 . 직관에 반하는 것처럼 보이지만 명명법 before_createcreate행동을 나타냅니다 . 새 개체를 인스턴스화하는 것은 개체가 아닙니다 create.
오류 발생

5

적어도 Rails 3.2.6의 부울 필드의 경우 마이그레이션에서 작동합니다.

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

퍼팅 1또는 0그 부울 필드이기 때문에 기본값으로, 여기에 작동하지 않습니다. true또는 false값 이어야합니다 .



2

마이그레이션 생성 및 사용 change_column_default은 간결하고 되돌릴 수 있습니다.

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

1

데이터베이스 지원 모델의 특정 속성에 대한 기본값을 설정하는 경우 SQL 기본 열 값 사용을 고려할 것입니다. 사용중인 기본값 유형을 명확히 할 수 있습니까?

이를 처리하는 방법에는 여러 가지가 있으며이 플러그인 은 흥미로운 옵션처럼 보입니다.


1
기본값과 제약 조건을 처리하기 위해 데이터베이스에 의존해서는 안된다고 생각합니다. 모든 항목은 모델 계층에서 분류되어야합니다. 이 플러그인은 ActiveRecord 모델에서만 작동하며 객체의 기본값을 설정하는 일반적인 방법은 아닙니다.
Lukas Stejskal

사용하려는 기본값의 유형에 따라 다르지만 자주 수행해야하는 작업은 아니지만 제약 조건이 실제로 데이터베이스와 데이터베이스 모두에 설정하는 것이 훨씬 낫다고 말하고 싶습니다. 모델-데이터가 데이터베이스에서 유효하지 않게되는 것을 방지합니다.
paulthenerd

1

새로 만들기 / 초기화를 재정의하라는 제안은 아마도 불완전 할 것입니다. Rails는 ActiveRecord 객체에 대해 allocate를 (자주) 호출하며, allocate 호출은 초기화 호출로 이어지지 않습니다.

ActiveRecord 객체에 대해 이야기하는 경우 after_initialize 재정의를 살펴보십시오.

다음 블로그 게시물 (내가 아님)은 유용합니다.

기본값 기본 생성자가 호출되지 않음

[편집 : SFEley는 Rails가 메모리에서 새 객체를 인스턴스화 할 때 실제로 데이터베이스의 기본값을 확인한다고 지적합니다. 저는 그것을 깨닫지 못했습니다.]


1

DB에서 기본 열 값으로 지정된 것처럼 기본값을 설정해야했습니다. 그래서 이렇게 작동합니다

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

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

after_initialize 콜백은 인자에서 속성을 설정 한 후 호출되기 때문에 속성이 설정되지 않았거나 의도적으로 nil로 설정 되었기 때문에 속성이 nil인지 알 방법이 없었습니다. 그래서 나는 약간의 내부를 들여다보고이 간단한 해결책을 가지고 왔습니다.

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

나를 위해 잘 작동합니다. (레일 3.2.x)



0

나는 여기에 비슷한 질문에 대답 했다 .. 이것을 수행하는 깨끗한 방법은 Rails attr_accessor_with_default를 사용하는 것입니다.

class SOF
  attr_accessor_with_default :is_awesome,true
end

sof = SOF.new
sof.is_awesome

=> true

최신 정보

attr_accessor_with_default 는 Rails 3.2에서 더 이상 사용되지 않습니다. 대신 순수 Ruby로이 작업을 수행 할 수 있습니다.

class SOF
  attr_writer :is_awesome

  def is_awesome
    @is_awesome ||= true
  end
end

sof = SOF.new
sof.is_awesome

#=> true

attr_accessor_with_defaultrails> 3.1.0
flynfish

귀하의 예에서 is_awesome은 @is_awesome == false 인 경우에도 항상 true입니다.
리치



-3

ActiveRecord 모델의 생성자를 재정의 할 수 있습니다.

이렇게 :

def initialize(*args)
  super(*args)
  self.attribute_that_needs_default_value ||= default_value
  self.attribute_that_needs_another_default_value ||= another_default_value
  #ad nauseum
end

2
코어 레일 기능을 변경하기에는 끔찍한 곳입니다. 다른 것을 깨뜨릴 가능성이 훨씬 적은 다른 훨씬 안정된 방법이 다른 답변에 언급되어 있습니다. 몽키 패치는 다른 방법으로 할 수없는 일에 대한 최후의 수단 일뿐입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.