Ruby on Rails where statement using user attribute - ruby-on-rails

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

Related

Ruby on Rails: getting associated values to display

I'm trying to create some kind of activity feed, and I'm having trouble getting the values I need to.
I have a controller with this action
def show
#user = User.find(params[:id])
#ideas = Idea.find(#user)
#lists = List.find(#user)
#li_array = (#lists + #ideas).sort{|a,b| -(a.created_at <=> b.created_at)}
end
I'm new to rails, and I'm trying to put together an array of values from the users of both ideas and lists. But I figured out that I can't do what I'm doing now because it will only pass the current user's id to match an id for Idea/List, but what I need to do is find the user's id column and search through based on #user.
I need to get all values from the users, what is the best method?
models
user.rb
has_many :lists
has_many :ideas, :through => :lists
list.rb
has_many :ideas
belongs_to :user
idea.rb
belongs_to :list
belongs_to :user
Thanks
You can simply do:
#user = User.find(params[:id])
#ideas = #user.ideas
#lists = #user.lists

How to define scope to get one record of a has_many association?

class User
has_many :posts do
def latest(report_date)
order(:report_date).where('report_date <= ?', report_date).limit(1)
end
end
end
class Post
belongs_to :user
end
I would like to retrieve the records of user with the last post for each user.
I could do this:
users = User.all.map{|user| user.posts.latest(7.weeks.ago).first}.compact
Is there a better way to write this? something like:
users = User.posts.latest(7.weeks.ago).all
if that were valid?
I tend to add something like this. Would it work in your case? It's nice because you can 'include' it in list queries...
class User < ActiveRecord::Base
has_many :posts
has_one :latest_post, :class_name => 'Post', :order => 'report_date desc'
...
end
In practice, you would do something like this in the controller:
#users = User.include(:latest_post)
And then, in the view where you render the user, you could refer to user.lastest_post and it will be eager loaded.
For example - if this was in index.html.haml
= render #users
you can access latest_post in _user.html.haml
= user.name
= user.latest_post.report_date

Nested Resource - Controller to filter by current_user also

Thanks to some help in another question, I now have a nested resource setup, and it is nearly working the way I need it to. This is a follow-up question about the controller.
Expenses have both a user, and a project that they belong to.
I would like to visit /projects/5/expenses, and see a list of all the expenses for that project, (which IS working), but also have it sensitive to the user that is currently signed in, so they only see their own expenses.
first the models:
class Expense < ActiveRecord::Base
attr_accessible :amount, :project_id, :user_id
belongs_to :project
belongs_to :user
end
each of the other models has "has_many :expenses", to complete the relationship.
so my route looks like:
resources :projects do
resources :expenses
end
And
class ExpensesController < ApplicationController
def index
#user = current_user
#project = Project.find(params[:project_id])
#expense_list = #project.expenses.all
end
How can I filter my #expense_list further by only showing the current_user's expenses?
You need a an additional condition to query the expenses based on the user that they belong to.
I would suggest that you create a scope in your Expense model
scope :for_user, lambda{ |user|
where( :user_id => user.id )
}
And you can do this in the controller:
#expense_list = #project.expenses.for_user(current_user).all

How to combine two scopes with OR

I have a tag feed and a friend feed.
I want to combine these two and build the ultimate "all" feed.
For friend feed:
class Post < ActiveRecord::Base
scope :friendfeed, lambda{|x| followed_by}
def self.followed_by(user)
where("user_id IN (?) OR user_id = ?", user.watched_ids, user.id)
end
end
For tag feed:
class Post < ActiveRecord::Base
scope :tagfeed, lambda{|x| infatuated_with}
def self.infatuated_with(user)
joins(:attachments).where("attachments.tag_id IN (?)", user.tags).select("DISTINCT pages.*")
end
end
And I would call something like this from the controller (I'm using Kaminari gem for pagination):
#tag_feed = Post.tagfeed(current_user).page(params[:page]).per(21)
#friend_feed = Post.friendfeed(current_user).page(params[:page]).per(21)
Now I want to have a universal feed, but I'm lost. Scopes are meant for narrowing down, but in this case I'm trying to do an OR operation. Doing stuff like
#mother_of_all_feed = #tag_feed + #friend_feed
would be redundant, and I wouldn't be able to control the number of posts appearing on a single page. How can I go about doing this? Thanks!
By the way, for tags I have association set up like this:
class Post < ActiveRecord::Base
has_many :attachments
has_many :tags, :through => :attachments
end
class Tag < ActiveRecord::Base
has_many :attachments
has_many :posts, :through => :attachments
end
class Attachment < ActiveRecord::Base
belongs_to :tag
belongs_to :post
end
There's a rails pull request for this feature (https://github.com/rails/rails/pull/9052), but in the meantime, some one has created a monkey patch that you can include in your initializers that will allow you to or scopes and where clauses in one query and still give you an ActiveRecord::Relation:
https://gist.github.com/j-mcnally/250eaaceef234dd8971b
With that, you'd be able to OR your scopes like this
Post.tagfeed(current_user).or.friendfeed(current_user)
or write a new scope
scope :mother_of_all_feed, lambda{|user| tagfeed(user).or.friendfeed(user)}
Answering my own question. I think I figured out a way.
where("pages.id IN (?) OR pages.id IN (?)",
Page.where(
"user_id IN (?) OR user_id = ?",
user.watched_ids, user.id
),
Page
.joins(:attachments)
.where("attachments.tag_id IN (?)", user.tags)
.select("DISTINCT pages.*")
)
It seems to be working so far, hope this is it!
Here's an example of how I combined two scopes.
scope :reconcilable, -> do
scopes = [
with_matching_insurance_payment_total,
with_zero_insurance_payments_and_zero_amount
]
where('id in (?)', scopes.flatten.map(&:id))
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..

Resources