ruby on rails undefined method for array - ruby-on-rails

I have a user who owns many phones
I have a a phone which has many call summaries
therefore my user has many call summaries
Now to the code that I have:
class User < ActiveRecord::Base
has_many :phones
has_many :call_summaries, :through => :phones
end
class Phone < ActiveRecord::Base
belongs_to :user
has_many :call_summaries
end
class CallSummary < ActiveRecord::Base
belongs_to :phones
end
I would like to generate a report that shows all the call summaries for the phones that belong to that certain user. I go into the controller and this is my code there:
def index
#phones = Phone.find(:all, :conditions => ["user_id = ?", #current_user.id])
#call_summaries = #phones.call_summaries.find(:all)
end
But this is returning this error:
undefined method `call_summaries' for #Array:0x476d2d0
Any help would be very much appreciated.

If you have the has_many :through relationship set up, you should just be able to do:
#call_summaries = #current_user.call_summaries
The problem with your method is that you're calling call_summaries on the #phones collection, rather than on individual phone instances.

#phones is an array of Phone objects. You have to iterate through that array and add each phone's call summaries to a single array. Try this:
#phones = Phone.find(:all, :conditions => ["user_id = ?", #current_user.id])
#call_summaries = #phones.inject([]){|arr, phone| arr + phone.call_summaries}

Off topic and just me being fussy, but a dynamic finder is more readable:
#phones = Phone.find_all_by_user_id(#current_user)

Related

Ruby on Rails where statement using user attribute

So basically I want something like this:
#network = Network.where(:id => current_user.network_ids).first
#posts = Post.where(:user.network.first => #network).order("created_at DESC")
But it basically doesn't recognize the column :user in the second line as the real column is user_id. I even tried:
#posts = Post.where('User.find(user_id).network.first =?',network )
with no luck
any ideas on how I could approach this.
model:
class User
has_and_belongs_to_many :network
has_many :posts
end
class Network
has_and_belongs_to_many :user
end
class Post
belongs_to :user
end
I basically want to filter the posts according to the network of the current user
So I simply solved the problem by using:
#posts = Post.where('user_id = ?', #network.user_ids)
As i can see, you have posts which belongs to a user and then user has many networks therefore your query should be
#posts = Post.where(:user.networks.first => #network).order("created_at DESC")
what your are calling is
:user.network.first
which states user has has_one relationship with network

NoMethodError in rails using multiple conditions

I can't seem to get the logic for my conditions to work for this query. I can get #showemail = PreferenceSetting.find(1) to work...but when I try to add conditions, it keeps throwing a "NoMethodError". I am fairly new at rails and am really stuck on this.
def show
#showemail = PreferenceSetting.where('user_id = ?', params[:u]).where('user_preference_id = ?', 1)
end
This is my code for the view
<%= #showemail.prefers %>
Every time I try to access the 'show' view it says "undefined method `prefers'.
My Models
class PreferenceSetting < ActiveRecord::Base
belongs_to :users_preference, inverse_of: :preference_settings
belongs_to :user, inverse_of: :preference_settings
end
class UserPreference < ActiveRecord::Base
has_many :preference_settings, inverse_of: :user_preference
end
find returns an instance whereas your where methods return an ActiveRecord::Relation object.
Adjust the code of your show action like this:
def show
conditions = {user_id: params[:u], user_preference_id: 1}
#showemail = PreferenceSetting.where(conditions).last
# you could also use: PreferenceSetting.find_by(conditions)
end

Active Relation: Retrieving records through an association?

I have the following models:
class User < ActiveRecord::Base
has_many :survey_takings
end
class SurveyTaking < ActiveRecord::Base
belongs_to :survey
def self.surveys_taken # must return surveys, not survey_takings
where(:state => 'completed').map(&:survey)
end
def self.last_survey_taken
surveys_taken.maximum(:position) # that's Survey#position
end
end
The goal is to be able to call #user.survey_takings.last_survey_taken from a controller. (That's contrived, but go with it; the general goal is to be able to call class methods on #user.survey_takings that can use relations on the associated surveys.)
In its current form, this code won't work; surveys_taken collapses the ActiveRelation into an array when I call .map(&:survey). Is there some way to instead return a relation for all the joined surveys? I can't just do this:
def self.surveys_taken
Survey.join(:survey_takings).where("survey_takings.state = 'completed'")
end
because #user.survey_takings.surveys_taken would join all the completed survey_takings, not just the completed survey_takings for #user.
I guess what I want is the equivalent of
class User < ActiveRecord::Base
has_many :survey_takings
has_many :surveys_taken, :through => :survey_takings, :source => :surveys
end
but I can't access that surveys_taken association from SurveyTaking.last_survey_taken.
If I'm understanding correctly you want to find completed surveys by a certain user? If so you can do:
Survey.join(:survey_takings).where("survey_takings.state = 'completed'", :user => #user)
Also it looks like instead of:
def self.surveys_taken
where(:state => 'completed').map(&:survey)
end
You may want to use scopes:
scope :surveys_taken, where(:state => 'completed')
I think what I'm looking for is this:
class SurveyTaking < ActiveRecord::Base
def self.surveys_taken
Survey.joins(:survey_takings).where("survey_takings.state = 'completed'").merge(self.scoped)
end
end
This way, SurveyTaking.surveys_taken returns surveys taken by anyone, but #user.survey_takings.surveys_taken returns surveys taken by #user. The key is merge(self.scoped).
Waiting for further comments before I accept..

How do I access records from a 2 level nested model

I have 3 models User,Listing and Message. What I want is for an authenticated user to have many listings. The listings then can have multiple messages. So the messages are tied to the user through the listing model. I am able to get a users listings but not able to get the users messages which he owns through the listings. Here are the associations that I currently have.
class User < ActiveRecord::Base
has_many :listings, :dependent => :destroy
end
class Listing < ActiveRecord::Base
belongs_to :user
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :listing
end
To create a message I simply do this;
#listing = Listing.find(params[:listing_id])
#message = #listing.messages.build(params[:message])
And getting the user's listing i have this;
#user_listings = Listing.user_listings(current_user)
But getting the messages tied to the user's listings proves to be elusive. What am I doing wrong or how do I go about this? help appreciated.
Still not sure where user_listings comes from but why not this:
#user = User.find(params[:user_id], :include => {:listings => :messages})
#user.listings.each do |listing|
listing.messages.each do |message|
#or
#user.listings.collect(&:messages).each do |message|
#or (just read about using authenticated user so the same as above like this
current_user.listings(:all, :include => :messages)...
Include prefetches all the listings' associated messages in one query in order that they're not fetched in the loop causing n+1 querying.
----------
Or another approach, if you don't need the listings data.
#messages.rb
def self.user_messages user_id
find(:all, :joins => :listings, :conditions => ["listings.user_id = ?", user_id])
#with pagination
def self.user_messages user_id, page
paginate(:all, :joins => :listings,
:conditions => ["listings.user_id = ?", user_id],
:per_page => 10, :page => page)
updated regarding your comment.
You may want to just add has_many :messages to the user class as well and add a user_id column to Message. Then you could just do current_user.messages
How about something like this:
class User < ActiveRecord::Base
has_many :listings, :dependent => :destroy
has_many :listing_messages, :through => :listings
That way you dont have to "tie" the messages with the user because it is always accessed through the listing association:
current_user.listing_messages.all
Or have I misunderstood your question?
If you have current_user pulled already. You can just access listings directly by calling
current_user.listings
instead of
#user_listings = Listing.user_listings(current_user)

Rails: order using a has_many/belongs_to relationship

I was wondering if it was possible to use the find method to order the results based on a class's has_many relationship with another class. e.g.
# has the columns id, name
class Dog < ActiveRecord::Base
has_many :dog_tags
end
# has the columns id, color, dog_id
class DogTags < ActiveRecord::Base
belongs_to :dog
end
and I would like to do something like this:
#result = DogTag.find(:all, :order => dog.name)
thank you.
In Rails 4 it should be done this way:
#result = DogTag.joins(:dog).order('dogs.name')
or with scope:
class DogTags < ActiveRecord::Base
belongs_to :dog
scope :ordered_by_dog_name, -> { joins(:dog).order('dogs.name') }
end
#result = DogTags.ordered_by_dog_name
The second is easier to mock in tests as controller doesn't have to know about model details.
You need to join the related table to the request.
#result = DogTag.find(:all, :joins => :dog, :order => 'dogs.name')
Note that dogs is plural in the :order statement.

Resources