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