Search or create multiple records more efficiently in Rails

I have an application that should send user invitations for events. When a user invites a friend (user) to an event, a new record connecting the user to the event is created if it does not already exist. My models consist of user, event and event_user.

class Event
    def invite(user_id, *args)
        user_id.each do |u|
            e = EventsUser.find_or_create_by_event_id_and_user_id(self.id, u)
            e.save!
        end
    end
end

Using

Event.first.invite([1,2,3])

I do not think this is the most efficient way to accomplish my task. I foresaw a method like

 Model.find_or_create_all_by_event_id_and_user_id

but does not exist.

Models without checks

class User 
  has_many :events_users 
  has_many :events 
end 
class EventsUser 
  belongs_to :events 
  belongs_to :users 
end 
class Event 
  has_many :events_users 
  has_many :users, :through => :events_users 
end
+3
source share
3 answers

Perhaps you can extract all existing records first, and then create all the missing records:

class Event
  def invite(user_ids, *args)
    existing_user_ids = event_users.where(user_id: user_ids).map(&:user_id)
    (user_ids - existing_user_ids).each do |u|
      event_users.create(user_id: u)
     end
  end
end

1 , event_users . , event_users, - , EventUser.

+6

? , , , , ..

, 100 , 100 "INSERT INTO events_models VALUES (x, x)" sql- (, , 100 "SELECT COUNT (*).." ). , AR, event_id, user_id).

Ruby/Rails, / /etc , ActiveRecord . , ( ActiveRecord), sql- (, ). .

Btw, e.save! :

, . find_or_create_by_ , .

+1

, raw sql:


self.connection.execute(%Q{insert into events_users (event_id,user_id) 
                             select distinct events.id,users.id from events,users 
                             where events.id = #{self.id} 
                             and users.id in ( #{user_ids.join(",")} )
                           }
                        )

user_ids . , , .

Since you have a connection model, you can use ar-import gem:

books = []
10.times do |i| 
  books << Book.new(:name => "book #{i}")
end
Book.import books
0
source

Source: https://habr.com/ru/post/1795633/


All Articles