I have the following in my events controller:
def index
#event = Event.search(params[:search]).events_by_category(params[:cat]).order(...).paginate(...)
end
And in my events model, I have the following class method:
def self.events_by_category(cat)
if cat == 0
all
elsif cat && cat != 0
where('category = ?', cat)
else
scoped
end
end
And in my view I have a standard search box for the search and dropdown for the category selection. The category options_for_select has an array that includes ["All Categories", 0] in it.
My question is: Why does this return no results instead of all results when All Categories is selected in the dropdown. And, when I change the array to ["All Categories", "ALL"] and the if statement to if cat == "ALL" it returns Undefined method 'order'?
I think it has something to do with stringing the search and events_by_category together in the controller, but searches and categories work just fine in conjunction when it's not All Categories being selected...
Any help would be GREATLY appreciated!
To answer your second question first: the problem is that your cat == "ALL" condition returns Event.all, which is a Ruby Array, not an ActiveRecord::Relation. order is an activerecord method not an array method, that's why you're getting the error Undefined method 'order'.
If you want to return all results for the category ALL, then change all to scoped (which will return a scope with no conditions on it). That will be chainable, so that you can call it with order and paginate.
As to your first question, params[:cat] is a string so you should be checking whether cat == "0" not cat == 0. I think that should solve the problem.
Your conditional, by the way, is a bit convoluted: you're testing if cat is 0, then checking that it is not 0 in the else statement, but you already know that it is not 0. I'd suggest simplifying your method code to this:
def self.events_by_category(cat)
(cat && cat != "0") ? where('category = ?', cat) : scoped
end
This says: if the category is present and not "0" (i.e. not the category "all results"), then return results for that category, if not return all results.
def self.events_by_category(cat)
if cat == "0"
all
elsif cat && cat != "0"
where('category = ?', cat)
else
scoped
end
end
The above will work.
Related
So I have a drivers (user table) which has a relationship with the subscriptions table. There are 3 different tiers available: Gold, Silver and a Free tier. What i want to do is group and order by tiers, so I'd have the golds together, silvers together etc in descending order.
What i have now in my controller:
class DriversController < ApplicationController
def index
order_subs = Driver.order_by_subs.all
def gold_drivers
Driver.select { |driver| driver.subscriptions.stripe_plan == 'price_xxx' || driver.subscriptions.stripe_plan == 'price_xxx'}
end
def silver_drivers
Driver.select { |driver| driver.subscriptions.stripe_plan == 'price_xxx' || driver.subscriptions.stripe_plan == 'price_xxx'}
end
def free_drivers
Driver.select { |driver| driver.subscriptions == 'null' || driver.subscriptions == ''}
end
#pagy, #drivers = pagy(
Driver.joins(:profile).select(
'drivers.*',
'(profiles.no_races + profiles.no_poles + profiles.no_podiums + profiles.no_wins) AS score'
).reorder(gold_drivers, silver_drivers, free_drivers, score),
page: params[:page],
items: 16
)
end
end
So my thoughts were I could select the records under a variable i.e gold_drivers and then add them as I would in the reorder section in the #pagy pagination section .reorder(gold_drivers, silver_drivers, free_drivers, score) At the moment when i run the page I get the error undefined method stripe_plan' for nil:NilClass` so i'm guessing it can't find the column. If it's a free user, they won't have a record in the subscription table. Thanks
EDIT: driver model
scope :is_gold, -> { where("drivers.subscriptions.stripe_plan == 'price_xxx'") || where("drivers.subscriptions.stripe_plan == 'price_xxx'") }
scope :is_silver, -> { where("drivers.subscriptions.stripe_plan == 'price_xxx'") || where("drivers.subscriptions.stripe_plan == 'price_xxx'") }
scope :is_null, -> { where("drivers.subscriptions.stripe_plan == ''") || where("drivers.subscriptions.stripe_plan" == null) }
scope :order_by_subs, -> { reorder(:is_gold, :is_silver, :is_null) }
I have to be honest your code is incredibly confusing. It looks like you can order by subs, but I guess you can't, I'm not sure what is working and what isn't looking at your code. I see what you are doing from our previous conversation and this is off. Like I said in my comment, I would focus on understanding the basics here before you dive into some of this stuff. I'm going to fix your method and explain along the way so it hopefully makes some more sense and either works, or shows you a path to getting it to work.
class DriversController < ApplicationController
def index
# because there is no # on this it is a local variable, it will not be available in the view. Wondering also why you didn't just use this for the select below. Also, if you can already order by subs why would you even need to select them, wasn't that the reason for selecting them like this in the first place?
order_subs = Driver.order_by_subs.all
# it is my understanding you want these in the view so we add the # symbol which makes it an instance variable and you access those variables in the view now
#gold_drivers = order_subs.select { |driver| driver.subscriptions.stripe_plan == 'price_xxx' || driver.subscriptions.stripe_plan == 'price_xxx'}
#silver_drivers = order_subs.select { |driver| driver.subscriptions.stripe_plan == 'price_xxx' || driver.subscriptions.stripe_plan == 'price_xxx'}
#free_drivers = order_subs.select { |driver| driver.subscriptions == 'null' || driver.subscriptions == ''}
# Not sure where your local variable 'score' is coming from, do you need to set that first?
#pagy, #drivers = pagy(
Driver.joins(:profile).select(
'drivers.*',
'(profiles.no_races + profiles.no_poles + profiles.no_podiums + profiles.no_wins) AS score'
).reorder(#gold_drivers, #silver_drivers, #free_drivers, score),
page: params[:page],
items: 16
)
end
end
O.k so now you are setting the drivers values as instance variables which can be accessed in your view.
I have this defined in a model called analysis_result.rb:
def total_matches
return 0 unless self.patterns
self.patterns.sum do |_, v|
matches = v.matches.try(:count) || 0
if v.additional.present? && v.additional['ggroup'].present?
bc_matches = v.additional['ggroup'].try(:count) || 0
else
bc_matches = 0
end
matches + bc_matches
end
end
I am trying to use it in in a view called _rable_row.haml in order to check beforehand if total_matches is 0 or not. If it is 0 I want to display a partial instead of letting the user go to the link.
This is the code from the view to check if analysis.results.total_matches != 0:
%tr.form-table__row{ class: ('form-table__row--disabled' if analysis.processing?) }
%td.form-table__data= check_box_tag "checkbox_object_ids[]", analysis.id
%td.form-table__data
- if analysis.results.total_matches == 0
= render partial: 'partials/shared/empty'
- elsif analysis.results.total_matches != 0
= link_to analysis.title, analysis, class: 'js-toggle', data: { href: "loading-#{analysis.id}" }
- unless analysis.viewed
%span.dashboard__icon.dashboard__icon--small.fa.fa-circle.text-info{ aria: { hidden: 'true' }, title: 'New' }
I get undefined method 'total_matches' for #<Mongoid::Criteria:0x00007fc51c5e3720>
Your problem comes from the definition of the method itself. You've declared your method total_matches on analysis_result.rb but you're calling analysis.results.total_matches.
I would write analysis.total_matches.
Bonus:
I would suggest a guard clause on top of your method total_matches
def total_matches
return 0 unless self.patterns
# ...
end
From what I could see in your updated question, your AnalysisResult belongs to Analysis. and total_matches is a instance method of Analysis.
But you are calling it like analysis.results.total_matches here, analysis.results will give you an active record array as analysis has_many results, on top of which you are trying to call total_matches.
You should try analysis.results.find the one instance and call total_matches on top of it.
For ex: analysis.results.last.total_matches(I am just taking .last for example)
I solved the problem differently:
- if analysis.results.sum(&:total_matches) != 0
only changed to this.
I have a call to ActiveRecord in my controller as so:
#configurations = EmailConfiguration.where(customer_id: '1', email_template: '1')
This will return all EmailConfigurations that have the correct parameters. Each record has a field_id and a the_value. I want to display the value in the view:
#configurations.where(field_id: 1).the_value
What do I need to add to the view to select a certain record within the collection that is returned by the database?
You can use select for a quick filter on arrays
#configurations.select {|c| c.field_id == 1}
that will return all collections with field_id = 1. If you know there is only one, you could chain it for a direct output:
#configurations.select {|c| c.field_id == 1}.first.the_value
#configurations.where(field_id: 1)
returns a collection of objects(array) even if there is only one result. If you would like to show only one you can do as suggested above:
#configurations.select {|c| c.field_id == 1}.first.the_value
If you want to show all of the "the_values" you can do
field_1_configs = #configurations.select do |c| c.field_id == 1
end
field_1_configs.map{|config| config.the_value }
I am trying to do something like this:
products = products.select { |product|
product.quantity > 0 || (
product.has_attribute?(:permit_negative_quantity) &&
product.permit_negative_quantity == true)
)
}
I am trying to leave only products association that has positive quantity, or, if the quantity is not positive, has the attribute permit_negative_quantity and it is set totrue.
This block keeps rejecting the products with a negative quantity. Am I missing something in the syntax? Is there a better way to do it?
It seems higher priority of && is causing this, try following:
products = products.select { |product| (product.quantity > 0 || (product.has_attribute?(:permit_negative_quantity) && product.permit_negative_quantity == true)) }
Ok finally i saw what i made wrong.
It was the :trueat the end of the condition which have to be truesince the table column is a boolean.
I have a Product model which has many Items. The application lists unique items which belong to a product. So think of items as inventory. The following query grabs featured items for a product and removes the first item (irrelevant, but it becomes a featured item, displayed separately, if you're curious).
# product.rb
has_many :items_in_stock, -> { Item.in_stock }, class_name: 'Item'
def featured_items
items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }[1..-1]
end
# item.rb
scope :in_stock, -> { where(status: 'in_stock') }
The trouble is when the feaured_items are empty, the method returns nil, and not a relation object. This means I get an error if I call #product.featured_items.any? on a product that has no items. If I remove the sort_by block, I get an empty relation object.
Is there a good way to handle this other than:
items = items_in_stock.select("DISTINCT ON (condition) id, items.*").order(:condition, :price)
if items.any?
items.sort_by { |item| item[:price] }[1..-1]
end
I can't reverse the ordering of the query because I get an error saying the order of the conditions in the order by statement must match the group conditions.
I'm confused...why call .any? on it then since nil is treated as false in ruby. If what you get back is nil then you know that you don't have any featured_items.
I ran this in irb and I think your issue is the [1..-1].
a = []
# => []
a.sort_by { |w| w.length }
# => []
a.sort_by { |w| w.length }[1..-1]
# => nil
The easiest way is to just do
items = items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }
items.any? ? items[1..-1] : items
Then you don't actually have to do a check in other parts of your code unless it's necessary.
instead of if items.any? you can use unless items.blank? if it's nil or empty, it won't run the condition
items.blank? checks both items.empty? and items.nil?
And of course you can use it in your featured_items
items = items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }[1..-1]
return Array.new if items.blank?
That way you know that result will be an array, no matter what
And for the proof, you can use .blank? on a nil object, and it works on nil itself, nil.blank? returns true