3

I've been looking for this for a while and can't seem to find an answer, although I think that it should be a pretty easy fix if you're more experienced with Rails than I am. I am trying to add multiple default_scope conditions to my Product model. My product model file is as follows:

class Product < ApplicationRecord
    has_many :order_items
    default_scope { where(active: true) }
    validates :name,  presence: true, length: { maximum: 300 }
    PRICE_REGEXP = /\A\d{1,4}(\.\d{0,2})?\z/
    validates :price, presence: true,
                      numericality: true,
                      format: { with: PRICE_REGEXP }
    validates :description, presence: true, length: { maximum: 1000 }, 
                            allow_nil: true
end

I would like to also add

default_scope -> { order(created_at: desc) }

so that new products on the product index page are in the format of newest first. I get an syntax error message anytime I do something like:

default_scope -> { order(created_at: desc) }, { where(active: true) }

or

default_scope -> { order(created_at: desc), where(active: true) }

or

default_scope -> { order(created_at: desc) where(active: true) }

I know that this is probably just a syntax thing that I'm not understanding. If anyone could give me advice on how to fix this it would be greatly appreciated! Thanks!

Sergey Moiseev
  • 2,953
  • 2
  • 24
  • 28

1 Answers1

7

I think what you are trying to do is this

default_scope -> { where(active: true).order(created_at: :desc)  }

So effectively you just had a syntax issue. When they added the new lambda scope syntax to rails it was a little unfamiliar to a lot of ruby developers due to its functional programming origins (given rails is object oriented language). Effectively the segment of code in {} acts like a block and executes the code inside. The where clause gets implicitly called on the model the scope is declared in. That where clause returns a ActiveRecord relation object (that is a collection of database records) which implements the order method that will sort the records in the relation by the attribute that is passed (in this case created_at) in descending (desc) or ascending (asc) order based on the parameter passed in.

Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85
C dot StrifeVII
  • 1,885
  • 1
  • 16
  • 21
  • This would be a better answer if you describe why it works. – max Oct 20 '16 at 01:51
  • 1
    It would have been sufficient to just write that you compose scopes in active record by chaining the method calls. – max Oct 20 '16 at 02:17
  • 1
    O I guess that explanation was over kill, but I am glad you included your comment. – C dot StrifeVII Oct 20 '16 at 02:21
  • 1
    Thanks man! Fixed my problem. The explanation was really helpful too! – Christian O'Rourke Oct 25 '16 at 23:33
  • @CdotStrifeVII what if I have to have an 'or' condition for Order, say I want to order on the the name if it exists otherwise order with created at. How do I achieve this? – Mahesh Mesta Jul 26 '18 at 12:15
  • @Mahesh Mesta I don't know if what you are asking is possible. imagine the scenario where 10 items 5 have names and created_at dates, 5 only have created_at dates unless you are sorting by both criteria and a nil name is an edge case you prepare for somehow with more complex logic. Give an example in a question and link it. – C dot StrifeVII Jul 27 '18 at 14:50