0

Trying to track down an issue updating a record, and came to this block:

# PATCH/PUT /artefacts/1
# PATCH/PUT /artefacts/1.json
def update
  respond_to do |format|
    if @artefact.update(artefact_params)
      format.html { redirect_to @artefact, notice: 'Artefact was successfully updated.' }
      format.json { render :show, status: :ok, location: @artefact }
    else
      format.html { render :edit }
      format.json { render json: @artefact.errors, status: :unprocessable_entity }
    end
  end
end

Now, to me, this looks like the definition of update is checking itself, but that can't be right since there's no code to parse artefact_params.

What am I missing? Where is the code that parses the params and saves the record?

(Using Rails 5.0rc1)

joshfindit
  • 611
  • 6
  • 27
  • You're asking to see the [Rails source code](https://github.com/rails/rails)? If you're willing to dig, you can see whatever you want. – MarsAtomic Jun 17 '16 at 00:56
  • I'm not familiar with what goes on behind the scenes. Am I asking to see the rails source code? Is that where the definition for `@artefact.update` would be kept? – joshfindit Jun 17 '16 at 00:58
  • `update` is part of Rails' RESTful API, so yes, that's where it would be found. Imagine if you were writing a method that saves data based on a collection of data it receives (the params hash). You'd unmarshall that data in your method and then call some `save` method with those unmarshalled params as arguments to save. Seems kind of straightforward to me, so I'm wondering why you're asking this question (e.g. do you have some other problem you're trying to resolve that lead you in this somewhat roundabout direction). – MarsAtomic Jun 17 '16 at 01:08
  • I envy you for having it seem straightforward. :) Yes, I have another tab open with the code question, just waiting for the 90min SO timeout. In Ruby fashion I like to dig out where the actual work is being done, tinker with it to see how it works, then change my code based on what I've learned. I'm looking through the Rails code to see what's going on behind the scenes. – joshfindit Jun 17 '16 at 01:23
  • If you add a link to the documentation of method that's being called here, I'll accept it as the answer. – joshfindit Jun 17 '16 at 01:24

1 Answers1

1

The code you're after can be found in the file rails/activerecord/lib/active_record/persistence.rb.

Here's the relevant code:

# Updates the attributes of the model from the passed-in hash and saves the
# record, all wrapped in a transaction. If the object is invalid, the saving
# will fail and false will be returned.
def update(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    assign_attributes(attributes)
    save
  end
end

And from rails/activemodel/lib/active_model/attribute_assignment.rb

def assign_attributes(new_attributes)
  if !new_attributes.respond_to?(:stringify_keys)
    raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
  end
  return if new_attributes.nil? || new_attributes.empty?

  attributes = new_attributes.stringify_keys
  _assign_attributes(sanitize_for_mass_assignment(attributes))
end

private

def _assign_attributes(attributes)
  attributes.each do |k, v|
    _assign_attribute(k, v)
  end
end

def _assign_attribute(k, v)
  if respond_to?("#{k}=")
    public_send("#{k}=", v)
  else
    raise UnknownAttributeError.new(self, k)
  end
end
joshfindit
  • 611
  • 6
  • 27
MarsAtomic
  • 10,436
  • 5
  • 35
  • 56