No MethodError when trying get active record id - ruby-on-rails-3

In model:
def self.get_by_slug(slug)
self.where("slug = ?", slug)
end
In controller:
#route: match '/category/:slug', :to => 'category#index', :as => "category_jobs"
#category = Category.get_by_slug(params[:slug])
#jobs = Job.where("category_id = ? AND expires_at > ?", #category.id, DateTime.now)
.paginate(:page => params[:page], :per_page => Jobeet::Application::MAX_JOBS_ON_CATEGORY_PAGE)
.order("expires_at desc")
When I trying get category.id in controller I am getting error:
undefined method `id' for #
Could somebody give me any advice?

If you expect a single record you should do:
#category = Category.get_by_slug(params[:slug]).first
because .where(something) doesn't return a single record.

Related

Getting error "Can't convert FixNum into Array"

class CartItemsController < ApplicationController
before_filter :initialize_cart, :check_not_signedin
def create
product = Product.find(params[:product_id])
kart = initialize_cart
qty = CartItem.select(:quantity).where(:cart_id => kart.id, :product_id => product.id)
if qty == 0
#item = CartItem.new(:cart_id => kart.id, :product_id => product.id, :quantity => qty+1)
if #item.save
flash[:success] = "Product added"
redirect_to category_products_path
end
else
if CartItem.where("cart_id = ? AND product_id = ?", kart.id, product.id).first.update_column(:quantity, qty+1)
flash[:success] = "Product updated"
redirect_to category_products_path
end
end
end
When I am trying to run this I'm getting the following error
"Can't convert FixNum into Array"
app/controllers/cart_items_controller.rb:17:in `create'
Please help!
The following line should return a ActiveRecord::Relation into qty:
qty = CartItem.select(:quantity).where(:cart_id => kart.id, :product_id => product.id)
You should use qty.count instead: qty.count == 0
Also, you can't add a ActiveRecord::Relation with 1 like this: qty+1. It will give you the error message you had.
I'm not sure what you are trying to do, but I suggest you use the debugger gem to help you troubleshoot your problem. Follow the guide here to setup, it's very simple to setup: http://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debugger-gem
Then, place debugger in your code:
product = Product.find(params[:product_id])
kart = initialize_cart
qty = CartItem.select(:quantity).where(:cart_id => kart.id, :product_id => product.id)
debugger # <---- here
if qty == 0
#item = CartItem.new(:cart_id => kart.id, :product_id => product.id, :quantity => qty+1)
if #item.save
Then you can find out more while you stopped at the debugger breakpoint, you can do stuff like:
qty.class
qty.count
# etc
Also, you can run rails console for testing.
I'm guessing that the following line is returning an Array:
CartItem.select(:quantity).where(:cart_id => kart.id, :product_id => product.id)
If this is the case then you can't simply add +1 to it on this line:
if CartItem.where("cart_id = ? AND product_id = ?", kart.id, product.id).first.update_column(:quantity, qty+1)
If this is not the case, can you point out which line is number 17 as pointed out in the error message.

complex search with thinking sphinx

I'd like to do a complex search with thinking sphinx:
Search for users which:
-> live in a city (city_id attribute)
-> or has hability to move to a city (mobile_cities association)
-> or live at a maximum distance from a lat/long point, the maximum distance is different for each user and set in a mobility_distance attribute.
For now I did that with 3 differents search, I volontary set a big per_page number, then i merge the 3 results on a single array, an then paginate this array :
#users living in the #city
search_set_living = search_set.merge({:city_id => #city.id })
users_living = User.search :with => search_set_living.dup,
:page => 1, :per_page => 1000
#users declaring hability to move to the #city
search_set_mobile = search_set.merge({:mobile_cities_ids => #city.id })
users_mobile = User.search :with => search_set_mobile.dup, :page => 1, :per_page => 1000
#users living at a maximum distance from the origin point(custom distance for each user, max 30km)
search_set_around = search_set.merge({"#geodist" => 0.0..30_000.0})
users_around = User.search :geo => [#search_latitude * Math::PI / 180 , #search_longitude * Math::PI / 180],
:with => search_set_around.dup,
:page => 1, :per_page => 1000
users_around_filtered = users_around.dup.delete_if{|user| (user.mobility_distance * 1000 )< user.sphinx_attributes['#geodist'] }
#merge the 3 results in a array
all_users = (users_mobile.flatten + users_around_filtered.flatten).uniq
#look for facets and paginate the array
#facets = User.facets :with => {:user_id => all_users.map(&:id)}
#users_to_display = all_users.paginate(:page => params[:page], :per_page => 10)
This is working fine but i'm not satisfied:
-performance are not so good,
-I want the ability to sort on multiple attributes like this :order => "created_at DESC, #relevance DESC"
I want to do the exact same search but in a single sphinx's search.
I know that I should use the "OR Logic with Attribute Filters" from the docs but I don't know how to mix it with a geo_search call...
I really have no idea how to do that,
can you guys help me ?
Many thanks,
The :sphinx_select option is definitely your friend here, as you've guessed. Let's piece it together bit by bit:
logic = [
"city_id = #{#city.id}",
"IN(mobile_cities_ids, #{#city.id}",
"GEODIST(lat, lng, #{lat}, #{lng}) < (mobility_distance * 1000)"
]
User.search :sphinx_select => "*, #{logic.join(" OR ")}) AS valid",
:with => {:valid => true}
Add pagination as you like, tweak the attribute names if needed (maybe your lat/lng attributes are named something else). I don't think you need the IF call around that custom attribute like in the docs, but if things aren't working when they should be, maybe give it a shot. Should be good in a facets call too.
Great ! Thank you so much. I just needed to correct a little your syntax (some parenthesis missing) in order to get it work.
I had to add per_page and page arguments too, don't know really why.
logic = ["city_id = #{#city.id}",
"IN(mobile_cities_ids, #{#city.id})",
"GEODIST(latitude, longitude, #{#search_latitude * Math::PI / 180}, #{#search_longitude * Math::PI / 180}) < (mobility_distance * 1000)"]
search_set_logic = search_set.merge({:valid => true})
#users_to_display = User.search :sphinx_select => "*, (#{logic.join(" OR ")}) AS valid",
:with => search_set_logic.dup,
:sort_mode => :extended,
:order => "visibility DESC, last_login_at DESC",
:page => params[:page], :per_page => 10

One efficient SQL call instead of 500

In my view, I've got a fiddly loop which creates 500 SQL queries (to get the info for 500 books). How can I avoid lots of SQL queries by loading a variable up in the controller?
My current (pseudo) code:
controller index action:
#books = Book.scoped.where(:client_id => #client.id).text_search(params[:query])
#feature_root = Book.multiple_summary_details_by_category( #books )
#...returns a hash of books
#features = #feature_root.to_a.paginate(:page => params[:page], :per_page => 4)
index.html.haml
= render :partial => "feature", :locals => { :features => #features }
_features.html.haml
- features.each_with_index do |(cat_name, array_of_books), i|
%h2
= cat_name
- array_of_books[0..10].each do |feature|
= link_to image_tag(feature[:cover], :class => "product_image_tiny"), book_path(feature[:book])
# more code
- array_of_books.sort_by{ |k, v| k["Author"] }.each do |feature|
- feature.each do |heading,value|
%span.summary_title
= heading + ':'
%span.summary_value
= value
What have you tried so far? It should be quite easy with standard ActiveRecord queries as documented in http://guides.rubyonrails.org/active_record_querying.html.
Also, instead of
array_of_books.sort_by{ |k, v| k["Author"] }
try something like
Book.order("author DESC")
(not sure about your exact model here) to let the db do the sorting rather than putting them in an array and let ruby handle it.

How to order by multi relation table 's field?

I need to generate a list of receipts in rails which need to be ordered by item's order relationship field (payment_method_meta_type.name).
Models :
Receipt
Deposit
PaymentMethodMetaType
In Deposit Model:
class Deposit < ActiveRecord::Base
belongs_to :payment_method_meta_type
has_many :receipts, :class_name=>"Receipt", :foreign_key=>"deposit_id",
:dependent => :destroy
end
I got an Array of Receipts in controller already :
#receipts = Receipt.find(:all, :conditions => ["date BETWEEN ? AND ?",
#start_date, #end_date], :order => "date DESC, id DESC",
:limit => limit, :offset => offset)
In the view I can show the payment_method_meta_type.name as well
- #receipts.each do |o|
%tr.
.....
%td #{o.receipt_number}
%td #{o.deposit.payment_method_meta_type.name}
.....
But how can I show the list by the order of receipts.deposit.payment_method_meta_type.name in the controller when I create the collection of the receipts array?
Try this:
#receipts = Receipt.all(:joins => {:deposit => :payment_method_meta_type},
:conditions => {:date => #start_date..#end_date},
:order => "payment_method_meta_types.name ASC",
:limit => limit, :offset => offset)
thx , I finally work it out, use 'include' in the query string
#receipts = Receipt.find(:all, :include => {:deposit => [:payment_method_meta_type] } ,:conditions => ["Receipts.business_date BETWEEN ? AND ?", #current_month_start_date, #current_month_end_date],:order => "tag_types.name , Receipts.business_date DESC",:limit => limit)

Correct this Rails/ruby method for me, please?

I've a post model with act-as-taggable-on gem. Both tables have timestamps.
I started with
def tags
#posts = current_user.posts.find_tagged_with(params[:tag], :order => "#posts.tags.updated_at DESC"])
end
And when that didn't work, I tried changing things and ended up with this mess.
def tags
#posts = current_user.posts.find_tagged_with(params[:tag])
#tags = #posts.tags.all
#posts = #tags(params[:tag, :order => "#posts.tags.updated_at DESC"])
end
I basically want to sort by when the tags was last updated.
Bonus: Sort by tag.updated_at or post.updated_at, but in this particular app, I'll be updating tags the most, so just first one will be fine.
Any help is appreciated.
You have to join the tags table in your find statement:
def tags
#posts = Post.find_tagged_with(
params[:tag],
:conditions => {:user_id => current_user.id},
:joins => :tags,
:order => 'tags.updated_at DESC',
:group => 'posts.id'
)
end
Note: Find the right conditions to select only posts from the current user. This example could work, though.