Here's an incoming form submission:
Started POST "/coupons" for ::1 at 2019-08-07 20:52:23 -0400
Processing by CouponsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xyBXVRs1DfQlkDxXlG/iTmxDMChOsPVfcgbNGX8dNOi5uPwfyBluAXcPFssxf5IQLPyoP2VWSPVjzZKeudwrHA==", "coupon"=>{"code"=>"TESTING", "discount_percent"=>"30", "discount_amount"=>"", "free_shipping"=>"0", "never_expires"=>"1", "uses_until_expiration"=>"", "user_email"=>"", "book_number"=>"", "category"=>"", "collection"=>"", "description"=>""}, "commit"=>"Create Coupon"}
It hits the controller, where the params are run through the strong parameters (whitelist) and assigned to the object (instance of the model):
def coupon_params
params.require(:coupon).permit(:code, :discount_percent, :discount_amount, :expires_on,
:never_expires, :uses_until_expiration, :redemptions, :user_email, :book_number, :description, :free_shipping,
:collection, :category)
end
def create
@coupon = Coupon.new(coupon_params)
respond_to do |format|
if @coupon.save
format.html { redirect_to @coupon, notice: "Coupon was successfully created." }
format.json { render :show, status: :created, location: @coupon }
else
format.html { render :new }
format.json { render json: @coupon.errors, status: :unprocessable_entity }
end
end
end
When you call save or update on the instance, the instance is persisted to the database. The actual implementation of this happens in the superclass of ActiveRecord::Base that all of your models descend from.
# File activerecord/lib/active_record/persistence.rb, line 274
def save(*args, &block)
create_or_update(*args, &block)
rescue ActiveRecord::RecordInvalid
false
end
This in turn calls create_or_update
# File activerecord/lib/active_record/persistence.rb, line 702
def create_or_update(*args, &block)
_raise_readonly_record_error if readonly?
return false if destroyed?
result = new_record? ? _create_record(&block) : _update_record(*args, &block)
result != false
end
You can keep on digging all the way down through a bunch more layers of indirection, but in the end, you get to the money:
# File activerecord/lib/active_record/persistence.rb, line 168
def _insert_record(values) # :nodoc:
primary_key_value = nil
if primary_key && Hash === values
primary_key_value = values[primary_key]
if !primary_key_value && prefetch_primary_key?
primary_key_value = next_sequence_value
values[primary_key] = primary_key_value
end
end
if values.empty?
im = arel_table.compile_insert(connection.empty_insert_statement_value)
im.into arel_table
else
im = arel_table.compile_insert(_substitute_values(values))
end
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
end
That's where you can see the Arel layer coming into play. `connection` is an instance of the connection adapter you configured, depending on which database you're using. When you call connection.insert, the `im` is passed to it, and that's an instance of the Arel AST representing the insert statement, filled in with the values assigned to the model instance.
Back to my live example above, here's the SQL that it got turned into (for MySQL):
Coupon Create (0.9ms) INSERT INTO `coupons` (`code`, `discount_percent`, `user_email`, `created_at`, `updated_at`, `description`, `collection`, `category`) VALUES ('TESTING', 30, '', '2019-08-08 00:52:23', '2019-08-08 00:52:23', '', '', '')
↳ app/controllers/coupons_controller.rb:32
Hope this little tour helps you better understand the "magic" happening in ActiveRecord and Rails.
Walter
> On Aug 7, 2019, at 11:53 AM, Noel <
noel...@gmail.com> wrote:
>
> Genuinely, I thank both of you for your insights. Without stretching this thread out any more, I want to figure out one last concept.
>
> Form data, based on what was mentioned above, is it that the headers dictate what is passed on as data to be persisted? Like where in the chain of events does the SQL know that this is the data to be persisted? I think that’s where I get foggy, I understand the concepts of the http request/response but at what point is the data from a form understood or decided or interpreted by SQL? That’s all in the adapter?
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
rubyonrails-ta...@googlegroups.com.
> To view this discussion on the web visit
https://groups.google.com/d/msgid/rubyonrails-talk/03b39e95-71af-4e6e-9f14-78047c70f74e%40googlegroups.com.