Add where condition to a Rails controller - ruby

Hi i have a controller in rails where i call all my players in database.
#candidates = Player.order("created_at DESC")
What i need is to show just the ones that have "active=1" un the database.. how can i add the where clause on this..
Tried this.. THE PROBLEM is that active is a table call "users" and im fetching "players" table..
#candidates = Player.where("active = ?", "1").order("created_at DESC")
Im lost :(
This is part of the player model
class Player < ActiveRecord::Base
belongs_to :user
Candidate model
class Candidate < ActiveRecord::Base
attr_accessible :country_id
end
Candidates controller
class CandidatesController < SecureController
skip_authorize_resource :only => [:index, :show]
# GET /players
# GET /players.json
def index
#candidates = Player.order("created_at DESC")
position = params[:position]
minyear = params[:minyear]
maxyear = params[:maxyear]
citizen = params[:nation]
#candidates = Player.scoped # for Rails 3
if params[:position].present?
#candidates = #candidates.where(position: position)
end
if params[:minyear].present?
#candidates = #candidates.where("birthday >= ?", minyear)
end
if params[:maxyear].present?
#candidates = #candidates.where("birthday <= ?", maxyear)
end
if params[:minyear].present? && params[:maxyear].present?
#candidates = #candidates.where("birthday >= ? AND birthday <= ?", minyear, maxyear)
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #candidates }
end
authorize! :show, :candidates
end

You need to join the users table:
Player.joins(:user).where("users.active = ?", "1").order("players.created_at DESC")
Also a better way to write the condition is:
Player.joins(:user).where(users: { active: true }).order("players.created_at DESC")

Related

Pundit with second devise model

I manage the authorization of users in my app with the pundit gem. Everything works fine for the user. Now I created a second devise model: Employers. I want to show a specific page to both logged in user as well as logged in employers. How do I do that?
Here is my policy for the model:
class CurriculumPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
def create?
return true
end
def show?
record.user == user || user.admin
end
def update?
record.user == user || user.admin
end
def destroy?
record.user == user || user.admin
end
end
And here is my controller for the index page which I want to make accessible:
class CurriculumsController < ApplicationController
skip_before_action :authenticate_user!, only: [:new, :create, :index]
before_action :set_curriculum, only: [:show, :edit, :update, :destroy]
def index
# #curriculums = policy_scope(Curriculum).order(created_at: :desc)
if params[:query]
#curriculums = policy_scope(Curriculum).joins(:user)
.where('users.job_category ILIKE ?', "%#{params[:query]}%")
.where(
'job_category ILIKE :query', query: "%#{params[:query]}%"
)
else
#curriculums = policy_scope(Curriculum).order(created_at: :desc)
end
end
private
def set_curriculum
#curriculum = Curriculum.find(params[:id])
end
def curriculum_params
params.require(:curriculum).permit(:doc)
end
end
You can have workaround here like below for each actions
def show?
true if #user.class.table_name == "employees"
end

Comparing time for nested associations

I'm in the process of building an application that'll accept a specific date from a user and which will then provide a list of events that have occurred prior to that date. While my code works if I'm looking for a specific value, I'm unable to perform a search when a particular date is passed in. Essentially i'd like to view all of the children elements that occurred previous to that particular date.
My Investments models is this:
class Investment < ApplicationRecord
has_many :transactions
def count
final_quanity = 0
self.transactions.each do |transaction|
final_quanity+= transaction.quantity
end
final_quanity
end
def average_price
total_spent = 0
self.transactions.each do |transaction|
total_spent += transaction.price
end
total_spent
end
end
My transactions model is this:
class Transaction < ApplicationRecord
belongs_to :investment
end
Investment controller
class InvestmentsController < ApplicationController
def index
if params[:date]
# #investments = Investment.includes(:transactions).where(transactions: {quantity:10})
#investments = Investment.includes(:transactions).where("date > ?", params[:date])
else
#investments = Investment.all
end
render json: #investments
end
end
I'd like to only return the specific transactions that occurred before the date entered, by I'm having difficulty returning with a conditional. As you can see from the blocked out code, I'm able to successfully return entries that have a specific value. What's the appropriate way to complete the active record query with a conditional?
What's strange is that the following works:
#transactions = Transaction.where("date < ?", date)
While this doesn't:
#investments = Investment.includes(:transactions).where("date > ?", date)
Instead I get an error message that these's no such column as "date".
Essentially what's the best way to perform this action:
#investments = Investment.includes(:transactions).where( :transactions => {:price => 100})
except determining if a value is greater than or less than instead of just matching.

Obtaining total for associated columns

I have 4 models, User, ImageSize, Frame and CartItem. The CartItem model holds all the id's for the 3 prior models, so
class CartItem < ActiveRecord::Base
belongs_to :image_size
belongs_to :user
belongs_to :frame
end
create_table "cart_items", force: :cascade do |t|
t.integer "user_id"
t.integer "image_size_id"
t.integer "frame_id"
end
class User < ActiveRecord::Base
has_many :cart_items
end
My first issue here is this doesn't seem correct, as in my association setup, but for now ill address that another time.
A Frame and ImageSize both have a price column and what I am trying to achieve is to get the sum of the price for Frame and ImageSize for the current user so that Ii can show a subtotal for the user that collects the sum for all cartitems
How can I write this query or collect this data? Here is what I have managed to put together, but surely there's an easier way?
def show
#frame_total = CartItem.frame_price_total(current_or_guest_user)
#image_size_total = CartItem.image_size_price_total(current_or_guest_user)
#subtotal = CartItem.subtotal(#frame_total, #image_size_total)
end
class CartItem < ActiveRecord::Base
def self.frame_price_total(u)
#price_array = []
user = includes(:frame).where(user_id: u)
user.each do |f|
#price_array << f.frame.price
end
#price_array.sum
end
def self.image_size_price_total(u)
#price_array = []
user = includes(:image_size).where(user_id: u)
user.each do |f|
#price_array << f.image_size.price
end
#price_array.sum
end
def self.subtotal(image_size_total, frame_size_total)
total = image_size_total + frame_size_total
BigDecimal.new(total).to_s
end
end
It look good but have N+1 query problem
def show
#user_frames = CartItem.includes(:frame).where(user_id: current_user)
frame_array = []
#user_frames.each do |f|
frame_array << f.frame.price
end
#frame_total = frame_array.sum
end

Rails callback after_save not setting attribute

I'm dealing with a problem on a after_save callback. I'm sure there is a easy solution, but I can't figure it out.
I have 3 models: User, Product, Bid. The Product table contains a boolean field "available", which is set default to true. If a User places a bid, the available field should be set to false.
I thought this should work with a callback on the bid model.
I can access and set the available field in the console by typing:
b = Bid.last
b.product.available = false
=> false
However I can't change it via the controller, so I think it doesn't execute the callback. What am I doing wrong?
Thank you all for your help!
product.rb
class Product < ActiveRecord::Base
has_one :bid
belongs_to :user
end
bid.rb
class Bid < ActiveRecord::Base
attr_accessible :product_id, :user_id, :product
belongs_to :product
belongs_to :user
after_save :set_product_status
def set_product_status
self.product.available = false
end
end
bids_controller.rb
...
def create
#user = current_user
product = Product.find(params[:product_id])
#bid = #user.bids.build(product: product)
respond_to do |format|
if #bid.save
...
Since bid belongs_to product, you should save the product too.
def set_product_status
self.product.available = false
self.product.save
end

How do I pass current_user into my model in Rails 3?

So I have a project model & user model. Each user belongs to a plan - that restricts the amount of projects they can have (i.e. plan_id = '1' can have 1 project, plan_id = '2' can have 3 projects, etc.).
I think I figured out how to do the actual restriction (i.e. in the project model, I do a validate :custom_method, and then define the method).
The issue is, that I need to reference the currently logged in user - i.e. current_user.
How do I do that given my code below ?
Projects Controller
def create
#project = current_user.projects.build(params[:project])
if #project.save
respond_with(#project, :status => :created, :location => #project) do |format|
flash.now[:notice] = 'Project was successfully created.'
format.html { redirect_to(#project) }
format.js { render :partial => "projects/show", :locals => {:project => #project}, :layout => false, :status => :created }
end
else
respond_with(#project.errors, :status => :unprocessable_entity) do |format|
format.js { render :json => #project.errors, :layout => false, :status => :unprocessable_entity }
format.html { render :action => "new" }
end
end
end
end
Project.rb
# == Schema Information
# Schema version: 20110131093541
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# description :string(255)
# notified :boolean
# created_at :datetime
# updated_at :datetime
# client_id :integer
#
class Project < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :client
has_many :stages, :dependent => :destroy, :order => 'created_at DESC'
has_many :comments
validate :number_of_projects
def number_of_projects
current_user.projects.count <= current_user.plan.num_of_projects
end
end
User.rb
# == Schema Information
# Schema version: 20110214082231
#
# Table name: users
#
# id :integer not null, primary key
# {edited for brevity}
# plan_id :integer
#
class User < ActiveRecord::Base
before_create :assign_to_trial_plan
has_and_belongs_to_many :projects
#{edited for brevity}
belongs_to :plan
def role_symbols
roles.map do |role|
role.name.underscore.to_sym
end
end
def space
total_size = 0
if self.uploads.count > 0
self.uploads.each do |upload|
total_size += upload[:image_file_size]
end
end
total_size
end
def assign_to_trial_plan
self.plan_id = '5' #make sure to update this if the Trial plan ID ever changes
end
end
If you're using current_user.projects.build, project.user is already current_user. Mission accomplished.
Edit: With HABTM, one of the users is current_user. You might consider a second association so you can say current_user.owned_projects.build and then project.owner.

Resources