I have a Rails app that displays Content
. Each piece of Content belong_to a Source
and a Source has_many Contents. Each Source consists of a name
and a domain
.
The Content also belongs_to an Edition
. The way my app is set up is, in the form to create/edit Editions
, I have nested the form fields for Contents
, using the Cocoon gem.
The nested fields for contents include a link
field. What I need to do is check the link
against the various domains
in the Sources table and set the relevant source_id
on the newly created/edited content.
I was thinking that I could set the relevant source_id
in the editions controller
on the update
or create
actions. However, since the only data I receive is a params hash with an embedded contents_attributes
hash (which holds no reference to the source_id
, since the source
is not set in the form), how can I set the source_id
using the 'link' submitted on the form?
Here's my create and update actions on the editions_controller:
def create
@edition = Edition.new(edition_params)
respond_to do |format|
if @edition.save
format.html { redirect_to @edition, notice: 'Edition was successfully created.' }
format.json { render :show, status: :created, location: @edition }
else
format.html { render :new }
format.json { render json: @edition.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @edition.update(edition_params)
format.html { redirect_to @edition, notice: 'Edition was successfully updated.' }
format.json { render :show, status: :ok, location: @edition }
else
format.html { render :edit }
format.json { render json: @edition.errors, status: :unprocessable_entity }
end
end
end
And here are the params used:
def edition_params
params.require(:edition).permit(:date,
:clicks,
:product_id,
contents_attributes: [:id,
:heading,
:body,
:link,
:top_story,
:section_id,
:_destroy
]
)
end
Should I have a hidden input on the form with the source_id? Or can this be done as is on the controller?
If you have the link
value set in contents form AND you have a logic to determine the source
from the value of link
, then you don't need to set source_id
in form OR in the controller.
Best place to set the source_id
would be in the model, so that it is always set no matter how you create the content
record i.e. from editions form, from console, or from some other controller. You won't have to worry about that in this case.
Having these associations and callbacks in your models should solve your purpose:
class Source
# field :name
# field :domain
has_many :contents
def self.fetch_from_link(link)
match_link_with_domains_and_return_source_record
end
end
class Edition
# field :date
# field :clicks
has_many :contents
accepts_nested_attributes_for :contents
end
class Content
# field :heading
# field :body
# field :link
# field :top_story
belongs_to :source
belongs_to :edition
before_validation :set_source
private
def set_source
# Set source *only* if not already set. You can change `||=` to `=` to set it always.
self.source ||= link && Source.fetch_from_link(link)
end
end