0

I have posts that associated with many users. When somebody comment one of them, my app creates a message that should be delivered to users associated with post. I want to associate all commented post users with new message. How to do it at once, without iterator?

users.each do |user| 
  user.messages << message
end
nobilik
  • 736
  • 9
  • 29

3 Answers3

4

It sounds like you are looking for ActiveRecord::Base.update_all - from the documentation:

Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the database. It does not instantiate the involved models and it does not trigger Active Record callbacks.

you can do something like:

users.update_all(:messages => "your message")

I guess you have all users related the same post in your users object.

for your reference you can check this link too regarding update_all:

Updates all records in the current relation with details given. This method constructs a single SQL UPDATE statement and sends it straight to the database. It does not instantiate the involved models and it does not trigger Active Record callbacks or validations. Values passed to update_all will not go through ActiveRecord's type-casting behavior. It should receive only values that can be passed as-is to the SQL database.

Gagan Gami
  • 10,121
  • 1
  • 29
  • 55
  • It's good answer! But I have HABTM relation between Users & Messages so I need to update table users_messages with user_ids + message_id. Will it work in this case? – nobilik Jan 04 '16 at 07:37
  • @nobilik : checkout this same question asked here http://stackoverflow.com/questions/3833529/update-all-through-an-association – Gagan Gami Jan 04 '16 at 07:46
1

AFAIK, this is not achievable with standard rails syntax, but you are still free to use plain old good SQL:

ActiveRecord::Base.connection.execute %Q{
  UPDATE users
  SET message_id = #{message.id}
  WHERE post_id = #{post.id}
}

The query above is likely not precisely correct, since you did not provide the relationship model, but I guess you get the point.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • 2
    you can do that using active record. `User.where(post: post).update_all(message: message)` or `User.where(post_id: post_id).update_all(message_id: message_id)`, but I am not sure if this is what he asked for. – Nafaa Boutefer Jan 04 '16 at 07:18
  • @NafaaBoutefer : I have just post the answer with same solution. After hitting post I see you have commented the same. You bit me wid 50 sec :D – Gagan Gami Jan 04 '16 at 07:20
  • 1
    I believe OP should mark the answer by @GaganGami as correct, since it provides more railsyish solution. – Aleksei Matiushkin Jan 04 '16 at 07:26
0

I saw this answer Can you supply arguments to the map(&:method) syntax in Ruby?

I do not recommend it but your can hack your way around by monkey patching the Symbol class in your initializer like

class Symbol
  def call(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

and in your User model adding a simple method like

def addMessage(message)
   self.messages << message
end

and in your code simply replace this

users.each do |user| 
  user.messages << message
end

with

users.map(&:addMessage.(message))

this is actually the same thing but it hides away the iterative style code to a simple map

I would NOT recommend doing this but I found it rather fun to play around with.

Community
  • 1
  • 1
Minato
  • 4,383
  • 1
  • 22
  • 28
  • Besides this is a nasty trick, that should be avoided, this approach _still calls `each`_ (implicitly, in `map`.) The question was about avoiding loops. – Aleksei Matiushkin Jan 04 '16 at 07:14
  • @mudasobwa I non recommended it like 2 times and mentioned the same thing in the ending statement .. It was just a fun way of doing I found and shared it. but as it goes its not recommended – Minato Jan 04 '16 at 07:21
  • My comment was not about “not recommending,” since it starts with “besides.” `map` by no means differs from `each`, that’s why this trick actually just senseless in terms of answering the original question. – Aleksei Matiushkin Jan 04 '16 at 07:23
  • @nobilik it sure is.. :P – Minato Jan 04 '16 at 07:44