Rails n elements before last - ruby-on-rails

In Rails I often do this:
Model.last(5).first
This retrieves element last-5.
Is there a built-in way of doing this?

The more common way is offset()
Model.offset(5).last
Edit (for lazy people):
1.8.7 :001 > User.first.id
=> 1
1.8.7 :002 > User.last.id
=> 143455
1.8.7 :003 > User.offset(5).last.id
=> 143450

Related

simple_format changes the text itself

In Rails 3.0, the helper method simple_format changes the parameter itself.
I expected that it only returns the wrapped text.
2.0.0-p648 :001 > Rails.version
=> "3.0.20"
2.0.0-p648 :002 > s = "Hello"
=> "Hello"
2.0.0-p648 :003 > helper.simple_format(s)
=> "<p>Hello</p>"
2.0.0-p648 :004 > s
=> "<p>Hello</p>"
I checked with Rails 4.2 and it doesn't change the text.
Can someone please explain it?
Sam
The difference between implementations of this method in Rails 4.2 and Rails 3.0 is that in Rails 3.0 the passed string is modified (mutated by gsub!) and in Rails 4.2 it's not (it just returns a new modified string):
Rails 4.2:
2.4.0 :006 > s = "hello"
=> "hello"
2.4.0 :007 > simple_format s
=> "<p>hello</p>"
2.4.0 :008 > s
=> "hello"
The source code of different implementations can be found in the documentation

Putting ~ after id fetches record

If we have an Active Record database say Users
User.find(id) works as expected:
But so does User.find('id~')
Also User.find('id~gibberish')
Is this a vulnerability or flaw of ActiveRecord?
How do I handle such requests appropriately?
This should help clear some things up, it is not ActiveRecord, it's Ruby's to_i method that you're seeing.
2.2.1 :001 > '11'.to_i
=> 11
2.2.1 :002 > '11~'.to_i
=> 11
2.2.1 :003 > '11~gibberish'.to_i
=> 11
This is not a vulnerability nor a flaw. If you're worried about input like this, I'd ask for an example where you think it could cause you harm.
Additionally if you'd like to be super defensive, use Integer(
2.2.1 :004 > Integer('11~gibberish')
ArgumentError: invalid value for Integer(): "11~gibberish"
2.2.1 :005 > Integer('11')
=> 11

Different result for Regexp match with Rails and Rubular?

I am using Rails 4.0.0 with Ruby 2.0.0 p247. I am writing an URL regexp matcher but I have no idea why it does not work:
2.0.0-p247 :033 > REGEXP = %r{\Ahttps:\/\/#{ Rails.configuration.aws[:bucket] }\.s3(-#{Rails.configuration.aws[:region]}|)\.amazonaws\.com\/(?<path>uploads\/.+\/(?<filename>.+))\?.+\z}.freeze
=> /\Ahttps:\/\/test-gem\.s3(-eu-west-1|)\.amazonaws\.com\/(?<path>uploads\/.+\/(?<filename>.+))\?.+\z/
2.0.0-p247 :034 > url = "https://test-gem.s3.amazonaws.com/uploads/2alrg16mvx6r-29590d114fb3257846c1a03330418da9/3031674-poster-p-1-for-25.jpg"
=> "https://test-gem.s3.amazonaws.com/uploads/2alrg16mvx6r-29590d114fb3257846c1a03330418da9/3031674-poster-p-1-for-25.jpg"
2.0.0-p247 :035 > REGEXP.match(url)
=> nil
But when I try to debug in things like Rubular, it does work. Any idea? Thanks!
Remove \?.+ in the end if your regexp
Might be a bug with Ruby 2.0.0. I'm using 2.1.3 and it works like you'd expect.
> r = /\Ahttps:\/\/test-gem\.s3(\A-eu-west-1\z|)\.amazonaws\.com\/(?<path>uploads\/.+\/(?<filename>.+))\z/
=> /\Ahttps:\/\/test-gem\.s3(\A-eu-west-1\z|)\.amazonaws\.com\/(?<path>uploads\/.+\/(?<filename>.+))\z/
> r.match("https://test-gem.s3.amazonaws.com/uploads/2alrg16mvx6r-29590d114fb3257846c1a03330418da9/3031674-poster-p-1-for-25.jpg")
=> #<MatchData
"https://test-gem.s3.amazonaws.com/uploads/2alrg16mvx6r-29590d114fb3257846c1a03330418da9/3031674-poster-p-1-for-25.jpg"
path:"uploads/2alrg16mvx6r-29590d114fb3257846c1a03330418da9/3031674-poster-p-1-for-25.jpg"
filename:"3031674-poster-p-1-for-25.jpg">

opening Array in ruby on rails console v. irb

I wish to make my code a little more readable by calling #rando on any array and retrieve a random element (rando because a rand() method already exists and I don't want there to be any confusion).
So I opened up the class and wrote a method:
class Array
def rando
self[ rand(length) ]
end
end
This seems far too straightforward.
When I open up irb, and type arr = %w(hi bye) and then arr.rando I get either hi or bye back. That's expected. However, in my rails console, when I do the same thing, I get ArgumentError: wrong number of arguments (1 for 0)
I've been tracing Array up the rails chain and can't figure it out. Any idea?
FWIW, I'm using rails 2.3.11 and ruby 1.8.7
Works fine in my case :
Loading development environment (Rails 3.0.3)
ruby-1.9.2-p180 :001 > class Array
ruby-1.9.2-p180 :002?> def rando
ruby-1.9.2-p180 :003?> self[ rand(length) ]
ruby-1.9.2-p180 :004?> end
ruby-1.9.2-p180 :005?> end
=> nil
ruby-1.9.2-p180 :006 > arr = %w(hi bye)
=> ["hi", "bye"]
ruby-1.9.2-p180 :007 > arr.rando
=> "bye"

In Ruby on Rails, should we use content_for?(:foobar)?

This is for Rails 3, almost always I think a content_for?(:foo) is followed by content_for(:foo) (in haml):
%title= content_for?(:title_for_page) ? "#{content_for(:title_for_page)} - Our great website" : 'Our great website'
So instead of doing 2 lookups, isn't it better to just do 1 lookup and use longer code:
- title_for_page = content_for(:title_for_page) # is "" when not previously set
%title= title_for_page.blank? ? 'Our great website' : "#{title_for_page} - Our great website"
? But if content_for? is implemented as a hash, then maybe it is super quick anyway, comparable to the blank? anyways?
A one-liner to solve the problem:
- title_for_page = (c = content_for(:title_for_page)).blank? ? 'Our great website' : "#{c} - Our great website"
Only way to find out is to test :)
ruby-1.9.2-p136 :001 > h = {:mike => "test"}
=> {:mike=>"test"}
ruby-1.9.2-p136 :004 > Benchmark.ms do
ruby-1.9.2-p136 :005 > h[:mike].present?
ruby-1.9.2-p136 :006?> end
=> 0.029087066650390625
ruby-1.9.2-p136 :007 > Benchmark.ms do
ruby-1.9.2-p136 :008 > h[:mike].blank?
ruby-1.9.2-p136 :009?> end
=> 0.011205673217773438
I am using present?, as per the source of content_for?
Interesting that blank? is faster than present?, isn't it? Time to explore.
Lets look at the source code for present?:
Woah, it turns out present? just calls blank? and negates it.

Resources