148

I'm wondering how the following is done in Rails 4 or if I just use the Rails 3 approach for using a lambda that can pass an argument the same way with 4 as I do with 3.

I'm pretty new to Rails 3 and trying to work through some samples running Rails 4.

Here is my Rails 3 code:

class Person < ActiveRecord::Base
  scope :find_lazy, lambda {|id| where(:id => id)}
end

# In console I can call
Person.find_lazy(1)

So if this is the Rails 4 way is to use the -> {}, that's a lambda, right? scope :all_lazy, -> { select("*") } What if I needed an argument. I tried a few different ideas and get argument errors in the console when using the -> {}.

strivedi183
  • 4,749
  • 2
  • 31
  • 38
kaplan
  • 4,109
  • 6
  • 30
  • 35

6 Answers6

315

I think it should be:

scope :find_lazy, -> (id) { where(id: id) }
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
lis2
  • 4,234
  • 1
  • 17
  • 9
  • 2
    [Supporting documentation](http://guides.rubyonrails.org/active_record_querying.html#scopes), section 14.1 specifically. – Dennis Feb 04 '14 at 18:40
  • 4
    Yay, helped me write `scope :in_daterange, ->(start_date, end_date) { where(created_at: start_date.to_date.beginning_of_day..end_date.to_date.end_of_day) }` – Epigene Mar 04 '15 at 12:41
  • 5
    Note that if you are using Ruby 1.9, the short lambda syntax does not allow a space between the arrow and a parameter (`scope :find_lazy, ->(param)`). In Ruby 2+, the space is allowed. [More info here...](http://ruby-journal.com/becareful-with-space-in-lambda-hash-rocket-syntax-between-ruby-1-dot-9-and-2-dot-0/) – furman87 Aug 22 '15 at 19:07
  • "Modern" syntex in Ruby `scope :find_lazy, -> id { where id: id }` – swordray Aug 07 '17 at 13:43
11

Ruby has not deprecated the old style of lambda either, so if you feel more comfortable using that by all means go for it.

I don't personally like the stabby lambda's syntax myself but eventually they will probably become the norm so it doesn't hurt to get used to them.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
Branden Silva
  • 1,406
  • 1
  • 11
  • 15
  • 6
    I like the syntax but it feels plain wrong to place the arguments between the arrow and the function body, while it should've been "(id) -> { where ... }" which would be much more appealing (and would neither break with my maths knowledge nor coffeescript syntax). In the end "->" says something like mapping values to a result. – hurikhan77 May 19 '14 at 17:18
  • I ran into a situation where using the old style in Rails 4.2 was returning incorrect boolean values from the database. It may not be officially deprecated, but using the updated syntax fixed the issue. – stevenspiel May 13 '15 at 19:26
  • 1
    @hurikhan77 Yeah it's disconcerting that the syntax conflicts with CoffeeScript http://coffeescript.org/#functions – Chloe May 04 '18 at 16:59
8

Rails 4, you can do:

scope :find_lazy, -> (id) { where(id: id) }

That was in the old ruby:

:id => id

Better hash:

id: id
sesperanto
  • 177
  • 2
  • 7
6

guy I was usually using the below programming syntax

scope :find_lazy, -> (id) { where(id: id) }

But when I was reviewing my code using Codacy I found it alerting me about this syntax

Use the `lambda` method for multiline lambdas.

I changed it to be and it working well

  scope :find_lazy, lambda {|id|
    where(id: id)
  }
Astm
  • 1,519
  • 2
  • 22
  • 30
2

To support associations:

scope :find_lazy, -> (object) { where(object_id: object.id) }
tokhi
  • 21,044
  • 23
  • 95
  • 105
2
scope :find_lazy, -> (id) { where(id: id) }

is equivalent with

self.find_lazy(id)
  where(id: id)
end

Based on ruby on rails guide: Using a class method is the preferred way to accept arguments for scopes.

There is no reason to use scopes together with lambdas in preference to class methods. It is a matter of personal preference. But, if you want to follow the guidelines, you should use the class method when arguments are involved.

mmsilviu
  • 1,211
  • 15
  • 25