I'm trying to figure out how to list my users by a certain string. In my app I have Artist who have one Artist_profile through has_one. In my Artist_profile, I have genre, which is what I'm trying to sort them out by. I do have it working at the moment with an if statement, but it looks through every single Artist and picks out the ones with the match. For example:
<% #artists.each do |artist| if artist.artist_profile.genre == "Rock" %>
<li><%= artist.id %></li>
<% end %>
I'm trying to get it something more like this, so it's less strain on my database:
<% #artists.rock.each do |artist| %>
<li><%= artist.id %></li>
<% end %>
and my model:
def self.rock
where(Artist.artist_profile.genre == "Rock")
end
However I get this error:
undefined method `artist_profile' for #<Class:0x6962940>
I think it's something to do with the has_one method, but can't seem to get this to work no matter what I try.
You should use the Joins method. It allows you to search fields in associated models. This differs from the Includes method as the Joins method doesn't include the results in the data. For example, if you wanted to list the artist genre instead of the id, then you would want to use Includes. In your code, you should put:
#artists = Artist.joins(:artist_profile).where("artist_profiles.genre" => "Rock")
You cannot call scope as Artist.artist_profile, it's an instance method
You can defind scope rock in ArtistProfile model
The result will look like this
class ArtistProfile < ActiveRecord::Base
belongs_to :artist
scope :rock, ->{where(genre: "Rock")}
...
and use it:
#rock_profiles = ArtistProfile.rock
<% #rock_profiles.each do |profile| %>
<li><%= profile.artist_id %></li>
<% end %>
Related
I am having some trouble while looping some association:
#=> member.rb
has_one :academic
#=> academic.rb
belongs_to :member
So far so good. However, when I loop through the association, I get:
undefined method 'each' for #<Academic:0x007fc98b2b7210>
Here's my view (show):
<% if !#member.academic.nil? %>
<% fields_academic = [:major, :second_major, :minor, :second_minor] %>
<h1>Academics</h1>
<% #member.academic.each do |academic| %>
<%= render 'database/shared/display', model_obj: academic, data: academic, fields: fields_academic %>
<% end %>
<% end %>
The code is stuck at the each method.
#member is defined as = Member.find(params[:id])
Any help will be gladly appreciated. Thank you in advance!
According to your code there are no multiple instances of academic related to the given member (it's defined using has_one relation).
The answer is: you cannot loop them.
The correct code for your view should be:
<% if #member.academic.present? %>
<% fields_academic = [:major, :second_major, :minor, :second_minor] %>
<h1>Academics</h1>
<%= render 'database/shared/display', model_obj: #memeber.academic, data: academic, fields: fields_academic %>
<% end %>
<% end %>
If your intention was to have many academics for a memeber, then use has_many instead.
class Member
has_many :academics
end
each should be used on a collection of records( I mean which results in a multiple records). Currently #member.academic will return a single record as it is a has_one relation between member and academic, so you can't loop with that. May be you should change your association to has_many :academics and loop it like <% #member.academics.each do |academic| %>
Method :each iterates over the block according to how this Enumerable was constructed. If no block is given, returns self. Enumerable is a mixin that provides to collections some useful methods. In your example academic is a not Enumerable, but single object. You should use has_many association.
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)
In a rails project, I use below code to retrieve data from Assignmenttable in database and show to user:
views/assignmenttables/_form.html.erb
<% task_list = Assignmenttable.find_by_current_user_id(user.id) %>
<% if task_list.blank? %>
<h1>It's blank</h1>
<% else %>
<% task_list.each do |task| %>
<%= task.id %>
<% end %>
<% end %>
data is retrive correctly from database, if task_list isn't empty this code is correct, but when task_list is empty, I get below error:
undefined method `each' for #<Assignmenttable:0x000000069541c8>
how can I handle this error?
The error you've got is caused because the object you called the .each method for is not a collection (multiple) - it's singular
Where
The way to fix this is to either use the .where method to call your data:
<%= task_list = Assignmenttable.where(user_id: current_user.id) %>
--
Associations
Or a better way will be to refactor your code to use the ActiveRecord associations which make Rails so appealing:
#app/models/user.rb
has_many :assignments
#app/models/assignment.rb # -> notice the name
belongs_to :user
current_user.assignments #-> allows you to call this in views
--
Model Names
Another thing you need to consider is your model names need to use CamelCase (AssignmentTable)
I have the following view to show the categories with the count
<% #categories.each do |category| %>
<% category.sub_categories.sort.each do |sub_category| %>
<li><%= link_to sub_category.name, "category/#{sub_category.slug}", title: sub_category.name.capitalize %> <%= sub_category.posts.where(status: 1).count %></li>
<% end %>
<% end %>
But I dont think using where in view is not good idea. Is there any other way to perform such operation.
I am getting correct count but I need better way to do this. can anyone help
Your Post model should have a scope on it that encapsulates this status logic:
class Post < ActiveRecord::Base
def self.active
where(status: 1)
end
end
Then call it like so from the view:
sub_category.posts.active.count
use scope to do the same thing, your solution is ok otherwise. you don't need to do this controller.
scope :active_posts, lambda{ where(status: 1)}
The only problem I see with this is it causes N+1 queries, because you do 1 query for the categories THEN another query for EACH category. This is ok with small quantities, however can cause serious performance problems later on.
1) I recommend you look into "counter_cache"ing:
- http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
2) OR upon activation/deactivation of Posts, create a method that will increment/decrement a attribute on the Post's Category (i.e. "active_posts")
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?