View/show has unknown column in Many2Many model - ruby-on-rails

I thought I could beat this to death by systematically moving through options.
It Won.
index.html.erb and form.html.erb work as things are now.
I have a many to many relationship between Bids and Contacts, with bids_contacts in between with bid_id and customer_contact_id in that table.
Here's the contacts then bids models:
has_and_belongs_to_many :bid_customer_contacts, :class_name => 'Bid',
:association_foreign_key => 'bid_id'
has_and_belongs_to_many :customer_contacts, :class_name => 'Contact', :foreign_key => 'customer_contact_id'
Nothing special in bids_controller.rb
The show.html.erb file errors with:
Mysql2::Error: Unknown column 'bids_contacts.contact_id' in 'on clause':
SELECT `contacts`.* FROM `contacts` INNER JOIN `bids_contacts'
ON `contacts`.`id` = `bids_contacts`.`contact_id'
WHERE 'bids_contacts`.`customer_contact_id` = 15
The code is:
<b>Customer Contacts:</b>
<% if !#bid.customer_contacts.empty? %> <<===============
<ul>
<% #bid.contacts.each do |bc| %>
<li><%= link_to(bc.name, bc) %></li>
<% end %>
</ul>
<% else %>
No Customer Contacts<br/>
<% end %>
I've tried contact_id in the M2M table rather than customer_contact_id, but I just get different errors.
Let me know if I need to share something else to get this mystery solved.
Thanks.

In your view, you're calling
#bid.customer_contacts
and then later
#bid.contacts
You probably want
#bid.customer_contacts
both times, since you defined the method this way with
has_and_belongs_to_many :customer_contacts ...
I assume you have customer_contact_id as a field in your database, but when you call .contacts your view looks for the contact_id field which doesn't exist.

Related

Rails: Cannot access column from a join-table in a partial

I want to access a column from a join-table in a partial. When I access this column in a "normal" view (e.g. fakeposts#index) it is working, however if I want to do the same in a partial, it does not work.
Example:
I have a users and a fakeposts table. For each user I want to display the fakeposts in a specific (randomized) order - namely based on a randomized_time column -, which is saved in a join table:
randomized_posts table:
user_id | fakepost_id | randomized_time
My Models look like this:
#user.rb
has_many :randomized_fakeposts
#fakepost.rb
has_many :randomized_fakeposts
# randomized_fakepost.rb
belongs_to :fakepost
belongs_to :user
In my fakepost_controller.rb I want to get the fakeposts for the current_user and add the column "randomized_time" to my selection:
My fakepost_controller.rb
def index
#fakeposts = Fakepost.joins(:randomized_fakeposts).where(randomized_fakeposts: {user_id: current_user.id}).select("fakeposts.*, randomized_fakeposts.randomized_time")
end
This is working: index.html.erb
<% #fakeposts.each do |post| %>
<%= post.randomized_time %>
<% end %>
This is not working: index.html.erb and my partial
#index.html.erb
<% #fakeposts.each do |post| %>
<%= render :partial => "layouts/individual-post", :locals => {:post => post} %>
<% end %>
#layouts/_individual-post.html.erb
<%= post.randomized_time %>
Error message
=> undefined method `randomized_time' for #<Fakepost:0x007f7752eeab58>
However, something like <%= post.created_at %> is working fine in my partial so I guess the way I call my partial is correct?
Ok, I've found the source of the error and for "outsiders" it was impossible to find (since I did not provide the whole code).
In my FakepostsController.rb I also had:
def index
# This line is the same line like in my original post
#fakeposts = Fakepost.joins(:randomized_fakeposts).where(randomized_fakeposts: {user_id: current_user.id}).select("fakeposts.*, randomized_fakeposts.randomized_time")
...
# This was the line which causes the error:
#pinned_fakeposts = Fakepost.where(pinned: true)
end
Because my #pinned_fakeposts did not include my "randomized_time" column (I did not .joins it), the error occured.
So what I did was:
#pinned_fakeposts = Fakepost.where(pinned: true).joins(:randomized_fposts).where(randomized_fakeposts: {user_id: current_user.id}).select("fakeposts.*, randomized_fakeposts.randomized_time")
Conclusion
So everything else was fine and it is possible to get your join column in a partial :).

Setting User Preferences using Normalized Model in Ruby On Rails

I'm building an application (web/iOS) that allows a user to set a series of preference options. The models/tables required include:
Users: stores user name, password, email address
Prefs: stores names/classes of preferences available, i.e., "sex"
PrefOpts: stores options for each preference, i.e., "Male" and "Female" for sex
UserPrefs: stores a selected PrefOpt for each User for each Pref
Model Specs:
class User < ActiveRecord::Base
has_many :user_prefs
has_many :prefopts, through: :user_prefs
end
class Pref < ActiveRecord::Base
has_many :prefopts
has_many :user_prefs
accepts_nested_attributes_for :prefopts
validates :name, presence: true
end
class Prefopt < ActiveRecord::Base
belongs_to :pref
has_many :user_prefs
has_many :users, through: :user_prefs
accepts_nested_attributes_for :user_prefs
end
class UserPref < ActiveRecord::Base
belongs_to :user
belongs_to :prefopt
end
For now, I want to set the user's preferences/options on the user "show" page, so when I pull up a user's record, I see a listing of all the preferences and for each a drop-down list of the available preferences for each option.
I have updated the Users controller to query back the preferences...
# GET /users/1
# GET /users/1.json
def show
#prefs = Pref.all
end
Also, I added to the routes file references under users:
resources :users do
resources :prefs do
get 'prefopts', on: :member
end
end
And this works fine: on a user's "show" page I can see all the available preferences when using this syntax:
<p>
<H2>Preferences</H2>
<ul>
<% #prefs.each do |pref| %>
<li><%= pref.name %></li>
<ul>
</ul>
<% end %>
</ul>
</p>
But when I add the code to loop over each "prefopt" for each pref, I get an error.
<p>
<H2>Preferences</H2>
<ul>
<% #prefs.each do |pref| %>
<li><%= pref.name %></li>
<ul>
<% #pref.prefopts.each do |prefopt| %>
<li><strong>Option: </strong><%= prefopt.name %></li>
<% end %>
</ul>
<% end %>
</ul>
</p>
Error message:
undefined method `prefopts' for nil:NilClass
Now, I've updated the pref scaffolding's show page to allow me to add and list prefopt records for each preference, and I'm using the same syntax from that view here.
If I take the error message at face value, it looks as if it thinks the "pref" is nil, but if that's the case why is the pref's name showing up correctly before I add in the prefopt?
Is there something I need to do in the view to pre-populate each pref's options? Or am I going about this all wrong? It there a best practice that I haven't found yet?
I've done extensive searching and have found some tips on working with many-to-many relationships, including:
http://www.createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/
I can see how I can save one user record sending a long a bunch of nested attributes, if only I can get the options to display.
I've also searched for best practices in saving user preferences and none of the examples I've found allow for the flexibility to dynamically add user preferences in the future by storing them in a separate model/table. I'm tempted to simply create one table for each preference and one join table for each user and each preference, but that's not a DRY approach. I can see how to save these nested attributes, if I can only list the options available to the user for each preference.
Thanks for any thoughts on this!
The error message you receive is because #pref is not set.
Rewrite your view like this:
<% #prefs.each do |pref| %>
<li>
<%= pref.name %>
<ul>
<% pref.prefopts.each do |prefopt| %>
<li><strong>Option: </strong><%= prefopt.name %></li>
<% end %>
</ul>
</li>
<% end %>
(Note I removed the #-sign before pref on line 5)

Rails 4 calling nested associations

I'm pretty new to rails but started having this issue today which i haven't experienced before. Currently working on an application with a few nested associations. While i can create and add save these nested associations through the parent association i can't seem to call on elements from the associated model very well. I can see the information has been saved but when I call for it i get the name of the model not what is in the name column of the table.
brew.rb
class Brew < ActiveRecord::Base
has_many :fermentables
has_many :extras
has_many :hops
has_many :yeasts
accepts_nested_attributes_for :hops
end
hop.rb
class Hop < ActiveRecord::Base
belongs_to :brew
end
show.html.erb
<%= #brew.name %>
<%= #brew.story %>
<%= #brew.walkthrough %>
<%= #brew.hops.name%>
The show displays mostly everything just fine except when it comes to #brew.hops.name. It only displays Hop.
When I go into rails console I can see that the name had been saved. But only when I do something like.
t = Brew.last
t.hops.name
results only in the word "hops"
but if i just say
t.hops
i get
` SELECT "hops".* FROM "hops" WHERE "hops"."brew_id" = ? [["brew_id", 28]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Hop id: 6, name: "Warrior",
brew_id: 28, created_at: "2013-06-09 22:09:19", updated_at: "2013-06-09 22:09:19">]> `
Brew and hops are in relation one-to-many, so #brew.hops returns set of all hops belonging to #brew. So, if you want to display all associated hops names, you should do something like this:
<% #brew.hops.each do |hop| %>
<%= hop.name %><br />
<% end %>
t.hops returns an object representing the has_many association itself, not an individual Hop record, and calling the name method on that association object gives the name of the class of the associated model (the Hop class).
So I think you are wanting to iterate over the list of associated Hops and print each of their names:
<%- #brew.hops.each do |hop| -%>
Hop: <%= hop.name %>
<%- end -%>

Ruby on Rails -- Saving and updating an attribute in a join table with has many => through

To simplify things, I have 3 tables :
Person
has_many :abilities, through => :stats
Ability
has_many :people, through => :stats
Stats
belongs_to :people
belongs_to :abilities
Stats has an extra attribute called 'rating'.
What I'd like to do is make an edit person form that always lists all the abilities currently in the database, and lets me assign each one a rating.
For the life of me, I can't figure out how to do this. I managed to get it to work when creating a new user with something like this:
(from the people controller)
def new
#character = Character.new
#abilities = Ability.all
#abilities.each do |ability|
#person.stats.build(:ability_id => ability.id )
end
end
From the people form:
<% for #ability in #abilities do %>
<%= fields_for "person[stats_attributes]" do |t| %>
<div class="field">
<%= t.label #ability.name %>
<%= t.hidden_field :ability_id, :value => #ability.id, :index => nil %>
<%= t.text_field :rating, :index => nil %>
</div>
<% end %>
<% end %>
This successfully gives me a list of abilities with ratings boxes next to them, and lets me save them if i'm making a new user.
The problem is that if I then load up the edit form (using the same form partial), it doesn't bring back the ratings, and if I save, even with the exact same ratings, it creates duplicate entries in the stats table, instead of updating it.
I realize I'm a terrible programmer and I'm probably doing this the wrong way, but how do I get the edit form to recall the current ratings assigned to each ability for that user, and secondly how do i get it to update the rating instead of duplicating it if the combination of person and ability already exists?
Shouldn't that be
Character
has_many :stats
has_many :abilities, through => :stats
Ability
has_many :stats
has_many :characters, through => :stats
Stat
belongs_to :character
belongs_to :ability
?
Also, is it Person or Character? You refer variously to both. (I'm going to go with Character in my answer)
I think you've fallen foul of the "I'll try to make a simplified version of my schema in order to attempt to illustrate a problem but instead make things more complex and muddle the issue by screwing it up so it doesn't make sense" syndrome. Anyway, there's a couple of issues i can see:
1) first thing is that you're adding all the possible abilities to a character as soon as they're created. This is silly - they should start out with no abilities by default and then you create join table records (stats) for the ones they do have (by ticking checkboxes in the form).
2) A simple way to manipulate join records like this is to leverage the "ability_ids=" method that the has_many :abilities macro gives you - referred to as "collection_ids=" in the api http://railsbrain.com/api/rails-2.3.2/doc/index.html?a=M001885&name=has_many
In other words, if you say
#character.ability_ids = [1,12,30]
then that will make joins between that character and abilities 1, 12 and 30 and delete any other joins between that character and abilities not in the above list. Combine this with the fact that form field names ending in [] put their values into an array, and you can do the following:
#controller
def new
#character = Character.new
#abilities = Ability.all
end
#form
<% #abilities.each do |ability| %>
<div class="field">
<%= t.label #ability.name %>
<%= check_box_tag "character[ability_ids][]" %>
</div>
<% end %>
#subsequent controller (create action)
#character = Character.new(params[:character]) #totally standard code
Notice that there's no mention of stats here at all. We specify the associations we want between characters and abilities and let rails handle the joins.
Railscasts episodes 196 and 197 show how to edit several models in one form. Example shown there looks similar to what you're trying to do so it might help you out (same episodes on ascicasts: 196, 197).

Setting up a feed with Rails

I have a country model and a places model - a country has_many places, and a place belongs_to a country. A place model also has_many posts (which belong_to a place). I would like to aggregate all the posts from places that belong to a certain country into a feed - rather like a friend activity feed on a social networking site. I'm having a bit of trouble figuring out the appropriate search to do, any help would be much appreciated! At the moment I have:
country.rb
has_many :places
has_many :posts, :through => :places
def country_feed
Post.from_places_belonging_to(self)
end
post.rb
belongs_to :place
scope :from_places_belonging_to, lambda { |country| belonging_to(country) }
private
def self.belonging_to(country)
place_ids = %(SELECT place_id FROM places WHERE country_id = :country_id)
where("place_id IN (#{place_ids})", { :country_id => country })
end
end
Then in the country show.html.erb file:
<h3>Posts</h3>
<% #country.country_feed.each do |post| %>
<%= link_to "#{post.user.username}", profile_path(post.user_id) %> posted on <%=link_to "#{post.place.name}", place_path(post.place_id) %> <%= time_ago_in_words post.created_at %> ago:
<%= simple_format post.content %>
<% end %>
This runs without any errors, but gives a feed of all the posts, rather than selecting the posts for that particular country. What's the best way to get this working? I've got a sneaking suspicion that I might be over-complicating matters...thanks in advance!
It looks like there's a syntax error in the subquery. places_id does not exist in the places table, so it really ought to read:
SELECT id FROM places WHERE country_id = :country_id
You'd think the invalid subquery would raise an exception, but it doesn't -- or else it is handled silently. Very odd.
But unless I'm missing something, you could replace all this just by using:
<% #country.posts.each do |post| %>
No?

Resources