I have the following models in my app
class User < ActiveRecord::Base
has_many :articles
has_many :tour_companies
has_many :accomodations
end
class Articles < ActiveRecord::Base
belongs_to :user
belongs_to :bloggable, :polymorphic => true
end
class TourCompany < ActiveRecord::Base
belongs_to :user
has_many :articles, :as => :bloggable
end
class Accommodation < ActiveRecord::Base
belongs_to :user
has_many :articles, :as => :bloggable
end
Now my problem is i want a logged in user to be able to write an article and use a form collection_select to select which one of his / her tour companies or accommodations the article should be associated with, how do i do it in rails 4? how do i select bloggable type and id from form collection select? I don't want nested resource
Since Rails 4.2, this can be handled via rails/globalid. This newer option is used by Rails' ActiveJob. It makes the parsing and lookup very simple to setup.
First, check your Gemfile.lock
for globalid
. For Rails 5, it is included.
The magic all happens in the model...
Article Model:
# Use :to_global_id to populate the form
def bloggable_gid
bloggable&.to_global_id
end
# Set the :bloggable from a Global ID (handles the form submission)
def bloggable_gid=(gid)
self.bloggable = GlobalID::Locator.locate gid
end
To get a feel for what this does, open up a rails console
. Play around with gid = TourCompany.first.to_global_id
and GlobalID::Locator.locate gid
.
Now the rest of your code is stock Rails stuff...
Articles Controller:
# consider building the collection in the controller.
# For Rails 5, this would be a `before_action`.
def set_bloggables
@bloggables = TourCompany.all + Accomodation.all
end
# permit :bloggable_gid if you're using strong parameters...
def article_params
params.require(:article).permit(:bloggable_gid)
end
Articles Form:
<%= f.collection_select(:bloggable_gid, @bloggables, :to_global_id, :to_s) %>
For more of a walk-through, Simple Polymorphic Selects with Global IDs blog post is helpful.
so i managed to finally do it. Here's how i did it in the views/articles/_form.html.erb
<div class="row">
<% bloggable_collection = TourCompany.all.map{|x| [x.title, "TourCompany:#{x.id}"]} +
Accomodation.all.map{|x| [x.title, "Accomodation:#{x.id}]}
%>
<p>Select one of your listing this article is associated with</p>
<%= f.select(:bloggable, bloggable_collection,:selected =>"#{f.object.bloggable_type}:# {f.object.bloggable_id}" ) %>
</div>
Then in the Articles Controller
#use regular expression to match the submitted values
def create
bloggable_params = params[:article][:bloggable].match(/^(?<type>\w+):(?<id>\d+)$/)
params[:article].delete(:bloggable)
@article = current_user.articles.build(article_params)
@article.bloggable_id = bloggable_params[:id]
@article.bloggable_type = bloggable_params[:type]
if @article.save
redirect_to admin_root_url, :notice => "Successfully created article"
else
render 'new', :alert => "There was an error"
end
end
And it should work!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With