Rails update only empty fields
Asked Answered
P

3

9

not having a lot of luck lately with answers in Stackoverflow (I think I'm the king of the tumbleweed award) but here goes anyway:

How can I update only fields that are empty when using activeRecord? I have this code:

master_info.update_attributes( {:originalTitle => slave_info.originalTitle,                                                                         
:starring => slave_info.starring,
:theatrical => slave_info.theatrical }

And would like something like:

master_info.update_attributes( {:originalTitle => slave_info.originalTitle, if !master_info.originalTitle.present?                                                                        
:starring => slave_info.starring, if !master_info.starring.present?
:theatrical => slave_info.theatrical if !master_info.theatrical.present? }

I could do it one line at a time, but am trying to avoid that:

master_info.update_attributes(:originalTitle => slave_info.originalTitle) if !master_info.originalTitle.present?

I read something like:

master_info.update_attributes( {:originalTitle => slave_info.originalTitle,                                                                         
                          :starring => slave_info.starring,
                          :theatrical => slave_info.theatrical }.reject{ |key, value| value.present?} )

But this doesn't work, it doesn't update anything, not even empty fields.

In fact, what would be ideal is to not have to repeat the field names since they are all named the same in both master and slave, but I can't do a .each on an activeRecord. But that's a secondary problem, the primary one is updating the empty fields.

Here's hoping this one doesn't get a tumbleweed :)

Purpurin answered 8/2, 2012 at 10:34 Comment(0)
E
10

A bit later here but thought I'd add how I did it in case someone finds it useful.

I used the function in the first answer and modified it to the below. As @ksol said in his comment, you probably want to keep the original update_attributes method as is, so I added this one to my model. I'm sure it could be included globally if you wanted it for multiple models.

def update_attributes_only_if_blank(attributes)
    attributes.each { |k,v| attributes.delete(k) unless read_attribute(k).blank? }
    update_attributes(attributes)
end

This removes any attributes from the hash unless the it already has a value. Then it updates the remaining attributes as normal.

Exorcist answered 25/6, 2013 at 6:9 Comment(0)
I
0

You can override the update_attributes in your model with something like this

def update_attributes(attributes)
  attributes.each{|attr| attributes.delete(attr) unless read_attribute(attr).empty?}
  super(attributes)
end

I don't tested this code then adjusts can be needed.

Islamize answered 8/2, 2012 at 16:14 Comment(11)
And in case you might want to keep the original way of updating around, you should define another method instead of overloading.Owenism
I'm sorry, I don't understand. I want to update the attributes if they are empty on the receiving end. This code seems like it removes the empty attributes from the incoming field. Or am I reading it wrong?Purpurin
I'm sorry, i changed to unless read_attribute(attr).empty?.Islamize
Fernando, I'm still a bit lost. Could you explain what the code does to make sure I'm reading it properly?Purpurin
The code remove each attribute not empty (readed directly in the object) of received attributes list and call the superclass update_attributes with the remainders. Then updates only the not empty. Is this that you need?Islamize
Yes, that is what I need. But how would I call that for the master_info object? Muito Obrigado!Purpurin
The call do not change, the controller continue the same: master_info.update_attributes(params[:slave_info])Islamize
Please excuse my ignorance, but I get an undefined method each for attributes error because attributes is not an array, it is an instance of an ActiveRecord (I think) since it was obtained with .find(id). How can I iterate through its attributes if it's not an array?Purpurin
attributes is that you pass to update_attributes, generally is a hash received through of web form (params). Do you get the database record with Model.find(params[:id]) and updates passing the form hash update_attributes(params[:model]). Then each exists to hash objects. You're not passing nil as parameter? What is the full error message?Islamize
I do get the database record with Model.find, but don't pass the attributes from a view template so no param[:model]. I pass it inside the same method inside the Dvd class where I get the Record: slave_info = find(slave), master_info.update_empty_attributes(slave_info)Purpurin
personally I'm not a big fan of overriding the ActiveRecord persistence methods. Those methods come with a known behavior and are part of the Rails convention. It's easier to implement your own version of the method and use that. That way when someone else comes along in your code they don't get any nasty surprises.Caddell
L
0

Modifying mchapman17's answer for Rails 6, minor change:

  def update_attributes_only_if_blank(attributes)
    attributes.each { |k, v| attributes.delete(k) unless read_attribute(k).blank? }
    update(attributes)
  end
Linskey answered 24/9, 2022 at 4:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.