둘 이상의 속성으로 find_or_create_를 가로막습니까?


202

find_or_create_by라는 활성 레코드에 편리한 동적 속성이 있습니다.

Model.find_or_create_by_<attribute>(:<attribute> => "")

그러나 둘 이상의 속성으로 find_or_create를해야하는 경우 어떻게해야합니까?

GroupMember라는 Group과 Member 간의 M : M 관계를 처리하는 모델이 있다고 가정 해 보겠습니다. member_id = 4 인 인스턴스는 여러 개있을 수 있지만 member_id = 4 및 group_id = 7 인 인스턴스는 두 번 이상 필요하지 않습니다.

GroupMember.find_or_create(:member_id => 4, :group_id => 7)

나는 이것을 처리하는 더 좋은 방법이있을 수 있다는 것을 알고 있지만 find_or_create 아이디어의 편의를 좋아합니다.

답변:


464

여러 속성을 다음과 연결할 수 있습니다 and.

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

( find_or_initialize_by기록을 즉시 저장하지 않으려는 경우 사용 )

편집 : 위의 방법은 Rails 4에서 더 이상 사용되지 않습니다. 새로운 방법은 다음과 같습니다.

GroupMember.where(:member_id => 4, :group_id => 7).first_or_create

GroupMember.where(:member_id => 4, :group_id => 7).first_or_initialize

편집 2 : 이 모든 것이 속성에 한정되는 것은 아닙니다.

https://github.com/rails/rails/blob/4-2-stable/guides/source/active_record_querying.md

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

되었다

GroupMember.find_or_create_by(member_id: 4, group_id: 7)

당신은 또한 같은 수 github.com/seamusabshere/upsert - 첫 번째 인수 찾거나 기록 만드는 데 사용되는 속성의 해시
시머 Abshere을

1
초기화 호출을 참고하는 것이 도움이된다 만들기 () 대신 first_or_create의 경우 호출 할 수있는 그) (새의
수밋 Bisht

이 사용법의 요점을 공유 할 수 있습니까? 나는 그 배치와 전화에 익숙하지 않습니다.
6ft Dan

많은 사람들이 아직 Rails 4를 사용하지 않기 때문에 Rails 3 코드 제거를 되돌 렸습니다.
Kyle Heironimus

find_or_create_by _ * () 함수는 Rails 4에서 더 이상 사용되지 않지만 find_or_create_by ()는 아닙니다. find_or_create_by ()를 사용해도됩니다. 이것이 추가 된 커밋을 확인하십시오. github.com/rails/rails/commit/… 및 공식 Rails 4.2 설명서 사용법 : guides.rubyonrails.org/v4.2.0/…
CodeExpress

33

이 스레드를 우연히 발견하지만 상황에 따라 변경 될 수있는 속성을 가진 오브젝트를 찾거나 작성해야하는 다른 사용자는 모델에 다음 방법을 추가하십시오.

# Return the first object which matches the attributes hash
# - or -
# Create new object with the given attributes
#
def self.find_or_create(attributes)
  Model.where(attributes).first || Model.create(attributes)
end

최적화 팁 : 어떤 솔루션을 선택하든 가장 자주 쿼리하는 속성에 대한 인덱스 추가를 고려하십시오.


8
한 가지 주목할 점은 대량 할당 할 수없는 속성은 처리하지 않는다는 find_or_create_by것입니다.
x1a4

1
마르코 Model.where(attributes).instance_eval{|q| q.first || q.create}.
hiroshi

3
find_or_create또한 where….first || create경쟁 조건을 도입하는 트랜잭션 사용의 이점도 있습니다
mrm

def self.find_or_create(attributes) self.where(attributes).first || self.create(attributes) end반복 할 필요가 없도록 말하고 싶습니다 Model
Augustin Riedinger

@AugustinRiedinger self메소드 본문 안에 필요하지 않습니다 (단어를 제거하려고하기 때문에!).
David Tuite

31

Rails 4에서는 다음을 수행 할 수 있습니다.

GroupMember.find_or_create_by(member_id: 4, group_id: 7)

그리고 사용법 where이 다릅니다 :

GroupMember.where(member_id: 4, group_id: 7).first_or_create

이것은 다음을 호출 create합니다 GroupMember.where(member_id: 4, group_id: 7):

GroupMember.where(member_id: 4, group_id: 7).create

반대로, find_or_create_by(member_id: 4, group_id: 7)의지는 다음을 요구 create합니다 GroupMember.

GroupMember.create(member_id: 4, group_id: 7)

레일 / 레일 관련 커밋 을 참조하십시오 .


16

블록을 전달하여 find_or_create 전달하면 객체가 새로 생성 된 경우 추가 될 추가 매개 변수를 전달할 수 있습니다. 검색하지 않는 필드가 있는지 확인하는 경우에 유용합니다.

가정 :

class GroupMember < ActiveRecord::Base
    validates_presence_of :name
end

그때

GroupMember.where(:member_id => 4, :group_id => 7).first_or_create { |gm| gm.name = "John Doe" }

이름이 "John Doe"인 새 GroupMember를 찾지 못하면 member_id 4 and group_id 7


4

넌 할 수있어:

User.find_or_create_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_create

또는 그냥 초기화하려면 :

User.find_or_initialize_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_initialize

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.