Gareth Burrows
Gareth Burrows

Reputation: 1182

appending to rails field value

I need to find and update a number of records in a Rails 3.2, Ruby 2 application. The following code successfully finds the records I want. What I need to do though is add " x" (including the space) to the email address of every user and I can't figure out how to do it.

This finds the records

User.joins(:account)
  .where("users.account_id NOT IN (?)", [1955, 3083, 3869])
  .where("accounts.partner_id IN (?)", [23,50])
  .where("users.staff = '0'")
  .where("users.admin = '0'")
  .where("users.api_user = '0'")
  .where("users.partner_id is null")
  .update_all(email: :email.to_s << " X")

but it's the last line I'm having problems with. Is this possible, or do I need to find the records another way?

Upvotes: 4

Views: 166

Answers (2)

Zoran
Zoran

Reputation: 4226

Try writing the last line like so:

.update_all("email = email || ' X'")

This uses SQL's string concatenation operator to append the X to the end of the emails.

Hope that helps!

Upvotes: 2

Wally Altman
Wally Altman

Reputation: 3545

The update_all method updates a collection of records, but unless you write your own SQL expression, it can only set one value. For example, if you wanted to overwrite all the email addresses with "X", you could do it easily:

User.joins(:account)
  .where("users.account_id NOT IN (?)", [1955, 3083, 3869])
  # ...other scopes...
  .update_all(email: "X")

In your case, what you really need to do is make individual updates to all these records. One way to do it is to find the records, then loop over them and update them one at a time:

users_to_update = User.joins(:account)
                      .where("users.account_id NOT IN (?)", [1955, 3083, 3869])
                      .where("accounts.partner_id IN (?)", [23,50])
                      .where("users.staff = '0'")
                      .where("users.admin = '0'")
                      .where("users.api_user = '0'")
                      .where("users.partner_id is null")

users_to_update.each do |user|
  user.update_attribute(:email, "#{user.email} X")
end

Another solution would be to use a SQL expression with update_all, as in Zoran's answer.

Upvotes: 2

Related Questions