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:migrate및 db:rollback직후. 동일한 결과로 받아 들인 대답이지만 적어도 가정합니다!
— gfd

1
이것은 레일 5.1에서 작동하지만 당신이해야 할 것입니다 .. 나에게 정답 up및 down@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_create은 create행동을 나타냅니다 . 새 개체를 인스턴스화하는 것은 개체가 아닙니다 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.