I am migrating a Rails app from 3.2 to 5.1, and it includes a simple enough model which includes a reference to the product type of the batch,
create_table "batches", :force => true do |t|
t.string "code"
t.integer "product_id"
t.boolean "recalled", :default => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
where, (edited down for clarity)
class Batch < ApplicationRecord
validates_presence_of :product
belongs_to :product
end
I am using will_paginate, so I have the following extract in my model to return a table of records,
def self.search(search, page)
if search
Batch.not_recalled.
where('batches.code LIKE ? OR products.code LIKE ? OR products.name LIKE ?',
"%#{search}%", "%#{search}%", "%#{search}%").
references(:product).
includes(:product).
order(:code).
page(page).per_page(30)
else
Batch.not_recalled.
includes(:product).
order(:code).
page(page).per_page(30)
end
end
And correspondingly, in my controller, I have,
# GET /batches/paginated
def paginated
#batches = Batch.search(params[:search], params[:page])
respond_to do |format|
format.html # paginated.html.erb
format.json { render json: #batches.to_json(include: [:product]) } # note the explicit 'include'
end
end
And in the partial to render the object, I have
<%= product = batch[:product] %> # Try and extract the nested record
<%= puts 'debug' %>
<%= puts batch.inspect %>
<%= puts product.inspect %>
<%= puts 'end debug' %>
<tr role="row" %> >
<td ><%= batch[:code] %></td>
<td><%= product ? product[:duplicate_batch] : 'N/A' %></td>
<td><%= product ? product[:code] : 'N/A' %></td>
<td><%= product ? product[:name] : 'N/A' %></td>
<td><%= link_to 'Show', batch %></td>
</tr>
Now, product is always nil, and the inspect shows the product nested record is NOT included.
I can also examine the JSON, and I can see the included 'product' entry ONLY if I explicitly include it in the format.json line of the controller, as shown above. As there isn't an equivalent syntax to specify the include during the format for the HTML render, I'm not able to render the nested product in HTML.
The really curious thing is I have another very similar model in the same app where this works just fine for HTML too, without an explicit include.
I am aware that ActiveRecord does not load until the last minute, but I am using includes with will_paginate, and I don't see why that would be an issue here. The inspect shows the record, not a ActiveRecord query (I believe).
Two questions:
Why is the nested include not included automatically?
If there's a
good reason for that, how do I specify it to include the product in
the HTML render?
Thanks.
add into model
scope :search, -> (search_param, page) do
includes(:product).
order(:code).
paginate_page(page)
end
Add there also search find part and u should be good
Also i would use activeModelSerializer for serializing objects or
https://github.com/Netflix/fast_jsonapi
Also go rails console
Batch.search(code, 1).to_json(include: [:product]) see whats gets displayed
Related
I'm trying to create a private messaging system for my website, and I am currently working on message replies. I've run into an ActiveRecord::AssociationTypeMismatch problem however. This is the error message:
ActiveRecord::AssociationTypeMismatch in RepliesController#create
Message(#58297820) expected, got String(#1635350)
I've been trying to figure out what the problem is for awhile now with no luck.
Below you will find my code for my migration, model, view, and controller.
Migration
def self.up
create_table :replies do |t|
t.integer :message_id, :null => false
t.integer :sender_id, :null => false
t.text :message, :null => false
t.timestamps
end
end
Model
class Reply < ActiveRecord::Base
belongs_to :message
validates_presence_of :message
cattr_reader :per_page
##per_page = 10
end
View
<% form_for(#reply) do |f| %>
<table>
<tr>
<td><%= f.text_area :message %></td>
</tr>
<%= f.hidden_field :message_id, :value => #message.id %>
<tr>
<td><%= f.submit 'Reply', :id => 'replySubmit' %></td>
</tr>
</table>
<% end %>
Controller
def create
account = Account.getAccountById(session[:user])
message = Message.find(
params[:reply][:message_id],
:conditions => ["messages.account_id=? or messages.sender_id=?", account.id, account.id]
)
if message
#reply = Reply.new
#reply.message_id = message.id
#reply.sender_id = account.id
#reply.message = params[:reply][:message]
if #reply.save
flash[:message] = "Reply successfully submitted."
redirect_to(messages_path)
else
flash[:warning] = "Message cannot be blank."
redirect_to(messages_path)
end
else
redirect_to(messages_path)
end
rescue ActiveRecord::RecordNotFound
render :template => "error"
end
I'd appreciate any help provided. I'll keep trying to figure out what the problem is.
Thank you.
Update: Stacktrace
RAILS_ROOT: C:/Users/redbush/Desktop/biomixr
Application Trace | Framework Trace | Full Trace
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record /associations/association_proxy.rb:259:in `raise_on_type_mismatch'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/associations/belongs_to_association.rb:22:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/associations.rb:1287:in `message='
C:/Users/redbush/Desktop/biomixr/app/controllers/replies_controller.rb:14:in `create'
Request
Parameters:
{"commit"=>"Reply",
"reply"=>{"message"=>"sssss",
"message_id"=>"4"},
"authenticity_token"=>"SMVfiolNAVPmLLU0eOWzx2jPFbujMtpyqQcs6A2Mxr0="}
Show session dump
Response
Headers:
{"Content-Type"=>"",
"Cache-Control"=>"no-cache"}
Your problem is that you have a relation to message and you also want to use a text field on the same model called message. When you create a relation you have access to some new methods that will step on the feet of other getter and setters.
To fix this change the name of the text field to another name and reflect the changes in your controller.
If you need more detail let me know.
The belongs_to relation creates a message attribute on your model, which expects an object of type Message. However, you also have a message attribute of type string. You can workaround this by using:
belongs_to :my_message, :class_name => :message
And the related message will be available as my_message, while the text field will be available as message.
In general, it seems like you're trying to handle too much of the relation work on your own - let rails do the work for you.
You have a clash in the design of your model. You have both an association and an attribute named message.
The error you are getting is because Rails is expecting you to fill up the association instead of the attribute.
I suggest changing your attribute from message to message_text, like so:
#reply = Reply.new
#reply.message_id = message.id
#reply.sender_id = account.id
#reply.message_text = params[:reply][:message]
Do make the changes in your migration file and run it too.
This is how you use autocomplete with jQuery Tokeninput and ActsAsTaggableOn.
In my situation i am using a nested form but it shouldnt matter. Everything below is code that works.
Code
Product Model:
attr_accessible :tag_list # i am using the regular :tag_list
acts_as_taggable_on :tags # Tagging products
Products Controller:
#1. Define the tags path
#2. Searches ActsAsTaggable::Tag Model look for :name in the created table.
#3. it finds the tags.json path and whats on my form.
#4. it is detecting the attribute which is :name for your tags.
def tags
#tags = ActsAsTaggableOn::Tag.where("tags.name LIKE ?", "%#{params[:q]}%")
respond_to do |format|
format.json { render :json => #tags.map{|t| {:id => t.name, :name => t.name }}}
end
end
Routes:
# It has to find the tags.json or in my case /products/tags.json
get "products/tags" => "products#tags", :as => :tags
Application.js:
$(function() {
$("#product_tags").tokenInput("/products/tags.json", {
prePopulate: $("#product_tags").data("pre"),
preventDuplicates: true,
noResultsText: "No results, needs to be created.",
animateDropdown: false
});
});
Form:
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => #product.tags.map(&:attributes).to_json %>
Issue 1(SOLVED)
Must have the line:
format.json { render :json => #tags.collect{|t| {:id => t.name, :name => t.name }}}
Note - You can use #tags.map here as well and you dont have to change the form either.
Below are the 2 issues on why you needed to do this:
I have the following Tag: {"id":1,"name":"Food"}. When I save a Product, tagged "Food", it should save as ID: 1 when it searches and finds the name "Food". Currently, it saves a new Tag with a new ID that references the "Food" ID, i.e. {"id":19,"name":"1"}. Instead, it should be finding the ID, showing the name, and doing a find_or_create_by so it doesn't create a new Tag.
Issue 2(SOLVED)
When I go to products/show to see the tags by doing <%= #product.tag_list %>. The name appears as "Tags: 1", when it really should be "Tags: Food".
How can I fix these issues?
You should define a route in your routes.rb which should handle products/tags path. You can define it like:
get "products/tags" => "products#tags", :as => :tags
Thus should give you a tags_path helper which should evaluate to /products/tags. This should get rid of the errors you mentioned in the question. Be sure to add this route before defining resources :product in your routes.rb
Now onto acts-as-taggable-on, I haven't used this gem, but you should look at method all_tag_counts documentation. Your ProductsController#tags method will need some changes on the following lines. I am not sure if its exactly what would be required, as I use Mongoid and can't test it out.
def tags
#tags = Product.all_tag_counts.(:conditions => ["#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?", "%#{params[:q]}%"])
respond_to do |format|
format.json { render :json => #tags.collect{|t| {:id => t.name, :name => t.name } }
end
end
little add-on:
If you want to create the tags on the fly, you could do this in your controller:
def tags
query = params[:q]
if query[-1,1] == " "
query = query.gsub(" ", "")
Tag.find_or_create_by_name(query)
end
#Do the search in memory for better performance
#tags = ActsAsTaggableOn::Tag.all
#tags = #tags.select { |v| v.name =~ /#{query}/i }
respond_to do |format|
format.json{ render :json => #tags.map(&:attributes) }
end
end
This will create the tag, whenever the space bar is hit.
You could then add this search setting in the jquery script:
noResultsText: 'No result, hit space to create a new tag',
It's a little dirty but it works for me.
There is a bug in Application.js code. There is an extra ) after "/products/tags.json". Remove the extra ). The code should be:
$("#product_tags").tokenInput("/products/tags.json", {
prePopulate: $("#product_tags").data("pre"),
preventDuplicates: true,
noResultsText: "No results, needs to be created.",
animateDropdown: false
});
I don't know if this is the entirety of your error, but you are not hitting the proper URL with the tokenInput plugin.
This
$("#product_tag_list").tokenInput("/products/tags.json"), {
should be
$("#product_tag_list").tokenInput("/products.json"), {
As I said, I don't know if this is the only problem you are having, but if you change this, does it work?
EDIT:
I have never used ActsAsTaggableOn. Does it create a Tag model for you to use?
From the looks of it on github, if you wanted to query all tags, you might have to use its namespace as opposed to just Tag, meaning ActsAsTaggableOn::Tag. For example, you can see how they access Tags directly in some of the specs.
I had problems with editing the tags if for example the model failed to validate,
I changed
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => #product.tags.map(&:attributes).to_json %>
to
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => #product.tag_list.map {|tag| {:id => tag, :name => tag } }.to_json %>
If the form failed to validate on first submission, it was creating tags as the ID's of the tags it had created on subsequent submissions.
Two notes: if you're getting the tags changed by numbers on the POST request, use:
tokenValue: "name"
And if you're trying to add non-existent tags, use (undocumented):
allowFreeTagging: true
Simply, a Contact can have various associated Time Windows, which may or may not be Active as a Schedule. To wit:
Models
class Contact < ActiveRecord::Base
has_many :schedules
has_many :time_windows, :through => :schedules
accepts_nested_attributes_for :schedules, :allow_destroy => true
end
class TimeWindow < ActiveRecord::Base
has_many :schedules
has_many :contacts, :through => :schedules
end
class Schedule < ActiveRecord::Base
belongs_to :contact
belongs_to :time_window
end
View
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<p>
<%= f.label tw.description %>
<%= hidden_field_tag "contact[schedules_attributes][][id]", schedule.id %>
<%= check_box_tag "contact[schedules_attributes][][time_window_id]",
tw.id, #contact.time_windows.include?(tw) %>
<%= check_box_tag "contact[schedules_attributes][][active]", nil,
schedule.active %>
</p>
<% end %>
This submits something like this:
Parameters: { "commit" => "Update", "contact" => {
"group_ids" => ["2"], "enabled" => "1",
"schedules_attributes" => [ { "time_window_id"=>"1", "id"=>"46"},
{ "time_window_id" => "2", "id" => "42", "active" => "on" },
{ "time_window_id" => "3", "id" => "43"},
{ "time_window_id" => "4", "id" => "44", "active" => "on"}],
"last_name" => ...
The update action in the controller is basically stock, except to handle another instance of another related model which I coded using the "Handling Multiple Models" example from the Advanced Rails Recipes book.
According to this API doc, I think the above ought to work. However, nothing about the Schedules is getting updated. This shows up in the server log:
[4;35;1mSchedule Update (0.2ms)[0m [0mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 42[0m
[4;36;1mSchedule Update (0.1ms)[0m [0;1mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 44[0m
(NetBeans is giving me those stupid "[0m"'s in the output. I don't know what's wrong there.)
The SQL shows that the "active" boolean field is getting set to 0 where checked. How do I get this to correctly set the active bit?
As a followup, how would I organize this to get rid of the Schedule "connection" at all? I'm thinking I need to submit a :_delete with the Schedule from the form, but how would I do that conditionally when a checkbox is involved?
Thanks for any help you can provide. Rails is turning out to be a vast subject for me, and I want to do it "right." I'm really close here, but there's got to be a way to make this -- not just correct -- but elegant. The view code just feels way too cumbersome to be proper Rails. ;-)
I've kept trying different approaches to this problem, and I've come up with this, which works. Mostly. The only problem is that it doesn't handle NOT having a "Schedule" for each "Time Window". The form will render, and I'll get a disabled check_box (to prevent me from trying to delete something that isn't there), but I don't have a way to add it back, and submitting without it throws off the params hash (and causes Rails to give me an "Expected Hash (got Array)" error)
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<% f.fields_for "schedules_attributes[]", schedule do |sf| %>
<p>
<%= sf.label tw.description %>
<%= sf.hidden_field :id %>
<%= sf.check_box :_destroy, :disabled => schedule.new_record? %>
<%= sf.check_box :active %>
</p>
<% end %>
<% end %>
Note that the "schedules_attributes[]" array will automatically give you an existing ID within the braces in your HTML (which is nice), but the _attributes hash is expecting an "id" alongside the other attributes in order to make sense of the sub-hashes.
One of the big lessons I've learned here is that the "check_box_tag" method doesn't (seem to) give me a paired-up hidden field for Rails to parse in the unchecked case. I would have expected this. Adding one in by hand made a mess, which led me to finally giving into the "fields_for" method, and trying many incarnations before finding the appropriate syntax to get what I wanted out of it.
I've realized that my model isn't quite appropriate in this setup, so I'm going to change it, but I was so close to this answer, I wanted to at least get to the point of being able to see the end before I moved on.
I have built a blog application w/ ruby on rails and I am trying to implement a search feature. The blog application allows for users to tag posts. The tags are created in their own table and belong_to :post. When a tag is created, so is a record in the tag table where the name of the tag is tag_name and associated by post_id. Tags are strings.
I am trying to allow a user to search for any word tag_name in any order. Here is what I mean. Lets say a particular post has a tag that is 'ruby code controller'. In my current search feature, that tag will be found if the user searches for 'ruby', 'ruby code', or 'ruby code controller'. It will not be found if the user types in 'ruby controller'.
Essentially what I am saying is that I would like each word entered in the search to be searched for, not necessarily the 'string' that is entered into the search.
I have been experimenting with providing multiple textfields to allow the user to type in multiple words, and also have been playing around with the code below, but can't seem to accomplish the above. I am new to ruby and rails so sorry if this is an obvious question and prior to installing a gem or plugin I thought I would check to see if there was a simple fix. Here is my code:
View: /views/tags/index.html.erb
<% form_tag tags_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search], :class => "textfield-search" %>
<%= submit_tag "Search", :name => nil, :class => "search-button" %>
</p>
<% end %>
TagsController
def index
#tags = Tag.search(params[:search]).paginate :page => params[:page], :per_page => 5
#tagsearch = Tag.search(params[:search])
#tag_counts = Tag.count(:group => :tag_name,
:order => 'count_all DESC', :limit => 100)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #tags }
end
end
Tag Model
class Tag < ActiveRecord::Base
belongs_to :post
validates_length_of :tag_name, :maximum=>42
validates_presence_of :tag_name
def self.search(search)
if search
find(:all, :order => "created_at DESC", :conditions => ['tag_name LIKE ?', "%#{search}%"])
else
find(:all, :order => "created_at DESC")
end
end
end
If I read your problem correctly, you want to return a row if the tag names for the row matches one of the words passed in the query string.
You can rewrite your search method as follows:
def self.search(search)
all :conditions => (search ? { :tag_name => search.split} : [])
end
If you need partial matching then do the following:
def self.search(str)
return [] if str.blank?
cond_text = str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values = str.split.map{|w| "%#{w}%"}
all(:conditions => (str ? [cond_text, *cond_values] : []))
end
Edit 1
If you want pass multiple search strings then:
def self.search(*args)
return [] if args.blank?
cond_text, cond_values = [], []
args.each do |str|
next if str.blank?
cond_text << "( %s )" % str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values.concat(str.split.map{|w| "%#{w}%"})
end
all :conditions => [cond_text.join(" AND "), *cond_values]
end
Now you can make calls such as:
Tag.search("Ruby On Rails")
Tag.search("Ruby On Rails", "Houston")
Tag.search("Ruby On Rails", "Houston", "TX")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah", ....) # n parameters
Caveat:
The wild card LIKE searches are not very efficient(as they don't use the index). You should consider using Sphinx (via ThinkingSphinx) OR Solr(via SunSpot) if you have lot of data.
You can try to set up ferret, or if you are really bend on just using rails, try this:
# Break the search string into words
words = params[:search].blank? ? [] : params[:search].split(' ')
conditions = [[]] # Why this way? You'll know soon
words.each do |word|
conditions[0] << ["tag_name LIKE ?"]
conditions << "%#{word}%"
end
conditions[0] = conditions.first.join(" OR ") # Converts condition string to include " OR " easily ;-)
# Proceed to find using `:conditions => conditions` in your find
hope this helps =)
Sounds like you need a full text search. The best search integration right now is with Sphinx and the Thinking_Sphinx plugin. I have used it on several projects and it's super easy to setup.
You do need to install sphinx on your host so if you are using a shared host that could present some issues.
You could also use full text search in a MyISAM MySQL database, but performance on that is pretty poor.
Once you have your sphinx installed you just put what you want to index in your model and call model.search. The results will be a list of model objects. It supports will_paginate as well.
I'd suggest looking at Searchlogic if you don't want to use a separate fulltext search engine (Ferret, Sphinx, etc). It makes simple searches extremely easy, although you may not want to use it in a public facing area without lots of testing.
Also check out the Railscast on it: http://railscasts.com/episodes/176-searchlogic
1.You can do some coding in your controller post as such:-
<pre>
def show
#post = Post.find(params[:id])
#tag_counts = Tag.count(:group => :name, :order => 'updated_at DESC', :limit => 10)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
</pre>
2.Now make some changes in your view file:-
<pre>
<b>Tags:</b>
<%= join_tags(#post) %>
<%unless #tag_counts.nil?%>
<% #tag_counts.each do |tag_name, tag_count| %>
<tr><td><%= link_to(tag_name, posts_path(:name => tag_name)) %></td>
<td>(<%=tag_count%>)</td>
</tr><% end %>
<%end%>
</pre>
3. And one important thing is that there should be many to many relationship between tags and post.
UPDATE: Solved. Thanks BusyMark!
EDIT: This is revised based on the answer below from BushyMark. I think I made all the suggested changes correctly, but I still can't get the post_type_id to save to the database when a user submits a message.
My app has a profile page. On the profile page, the owner of the page can type an update and hit "submit." The update messages appear without the page reloading (i.e. Ajax).
It basically looks like your Twitter home page. BUT, there's also a message "type" that our users select when typing an update. The message type is a pre-populated list. I've made it a model and load it as seed data in the app.
So: there is a profile model, a post model, and a post_type model.
profile has_many :posts
post belongs_to :post_type
post_type has_many :posts
The post model also has this: attr_accessible :message, :post_type_id
Routes.rb looks like this:
map.resources :users, :has_one => :profile, :has_many => :posts
map.resources :post_types
The posts controller has this method for creating the posts:
def create
#post = current_user.profile.posts.build(:message => params[:message], :post_type_id => params[:post_type_id])
if #post.save
redirect_to user_profile_path
else
flash[:notice] = "Message failed to save."
redirect_to user_profile_path
end
end
The "show" view for the profile page where this all occurs looks like this:
<% form_tag(:controller => "posts", :action => "create") do %>
<%= label_tag(:message, "Update your people") %><br />
<%= text_area_tag(:message, nil, :size => "27x3") %>
<div class="updateSubmit"><%= submit_tag("Update") %></div>
<%= label_tag(:type_id, "Optional: Update type", :class => 'typeLabel') %>
<%= collection_select(:post, :post_type_id, PostType.all, :id, :name, {:prompt => true}) %>
<% end %>
<% #profile.profile.posts.each do |c| %>
<%=h c.message %></div>
<p><%=h c.post_type %></p>
<p>Posted <%=h time_ago_in_words(c.created_at) %> ago</p>
<% end %>
That's the background. Here's the problem. With my current setup, when the user submits his message, the message gets sent to the posts database table, BUT the post_id does not.
My select tag is rendering like this:
<select id="post_post_type_id" name="post[post_type_id]"><option value="">Please select</option>
This is the output I get in the log when I submit a post:
Processing PostsController#create (for IP at 2009-09-03 03:03:08) [POST]
Parameters: {"message"=>"This is another test.", "commit"=>"Update", "action"=>"create", "authenticity_token"=>"redacted", "post"=>{"post_type_id"=>"3"}, "controller"=>"posts", "user_id"=>"1"}
User Load (0.3ms) SELECT * FROM "users" WHERE ("users"."id" = 1)
Profile Load (0.7ms) SELECT * FROM "profiles" WHERE ("profiles".user_id = 1) LIMIT 1
Post Create (0.5ms) INSERT INTO "posts" ("message", "updated_at", "post_type_id", "profile_id", "created_at") VALUES('Hello', '2009-09-03 20:40:24', NULL, 1, '2009-09-03 20:40:24')
Here's the relevant parts of my schema, updated per BushyMark's comments:
`create_table "post_types", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end`
`create_table "posts", :force => true do |t|
t.text "message"
t.integer "profile_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "post_type_id"
end`
Couple things going on here I see so far:
type is a reserved word in Rails. It is used for single table inheritance. If you change your column name to something like "post_type" it should help immensely in trying to solve random issues. I went through this a while back and was beating my brains out before I knew about STI.
Also, you have a type_id in your post . . . but I didn't see that your post :belongs_to :type . . . don't forget that a model with the foreign key needs this declaration to use all the ActiveRecord associations.
Hope this helps!
Another Edit: I noticed that in your insert statement, it appears you have a "type" column? This will also cause issues when using relationships. Are you using a separate 'type' model? Can you possibly post your schema if any of the above statements don't help?
In ActiveRecord, a type column is reserved and will not display properly(back to my statement about Single Table Inheritance). At this point I strongly recommend getting rid of your type and type_id columns, and giving your Post a "post_type_id" column.
Then once you create a separate post_type model that has_many :posts you will want to make sure your Post :belongs_to :post_type (because it has the foreign key). Once you do that, you will be able to call post_object.post_type and it will return the model relationship you are looking for.