Rails find with a block
It's a shortcut for .to_a.find { ... }
. Here's the method's source code:
def find(*args)
if block_given?
to_a.find(*args) { |*block_args| yield(*block_args) }
else
find_with_ids(*args)
end
end
If you pass a block, it calls .to_a
(loading all records) and invokes Enumerable#find
on the array.
In other words, it allows you to use Enumerable#find
on a ActiveRecord::Relation
. This can be useful if your condition can't be expressed or evaluated in SQL, e.g. querying serialized attributes:
Consumer.find { |c| c.preferences[:foo] == :bar }
To avoid confusion, I'd prefer the more explicit version, though:
Consumer.all.to_a.find { |c| c.preferences[:foo] == :bar }
Rails, how to use a block in where statement
:where does not accept block condition.
You can use plain SQL, like Customer.where('id = main')
if it works for you.
Or, you can go with more complex way... using arel tables.
consumer = Consumer.arel_table
Consumer.where(consumer[:id].eq(consumer[:main])).to_sql
=> "SELECT \"consumers\".* FROM \"consumers\" WHERE \"consumers\".\"id\" = \"consumers\".\"id\""
Rails find_or_create_by where block runs in the find case?
As far as I understand block will be executed if nothing found. Usecase of it looks like this:
User.find_or_create_by_name("Pedro") do |u|
u.money = 0
u.country = "Mexico"
puts "User is created"
end
If user is not found the it will initialized new User with name "Pedro" and all this stuff inside block and will return new created user. If user exists it will just return this user without executing the block.
Also you can use "block style" other methods like:
User.create do |u|
u.name = "Pedro"
u.money = 1000
end
It will do the same as User.create( :name => "Pedro", :money => 1000 )
but looks little nicer
and
User.find(19) do |u|
..
end
etc
Rails Find a Record Within ActiveRecord::Relation Object without querying database again
Once the relation has been loaded, you can use regular array methods. find
is actually a very interesting method here - if block is specified, it will be delegated to the relation target:
@blogs.find {|b| b.id == 1}
Ruby - Array.find, but return the value the block
[1, 2, 3].detect { |i| i += 1; break i if i == 2 }
# => 2
[1, 2, 3].detect { |i| i += 1; break i if i == 10 }
# => nil
Why is the first value of a Rails find_or_create_by block always nil in database?
The commas that mu is too short spotted are what's actually causing the problem here.
This is interpreted by Ruby as trying to assign an array to start_date_time
with a side effect of setting all the other attributes along the way. As this isn't a valid value for the field it ends up remaining as nil
.
It looks like this stems from a slight misunderstanding:
Rails should create a new TrainingEvent with all of the attributes passed in the block
The block isn't for passing a list of attributes. The block is code which in the case of create
is passed the new model object so that you can do anything you'd like with it prior to it being saved. Remove the commas and you'll be fine!
If you're curious, here's a simpler example that demonstrates how your code is being interpreted:
> x = 1, y = 2
This results in x
having the array value [1, 2]
and y
having the value 2
implementing find_or_create_by when find involves single attribute but create involves multiple attributes
find_or_create_by takes a block that will be applied only on create. It'll look for a record by the attribute you provide and if none is found, will create one with the block attributes you specify.
In your case this would look like:
user = User.find_or_create_by(email: recipient) do |user|
user.password: Devise.friendly_token.first(6),
user.confirmed_at: DateTime.now
end
Find and replace in a block of text
Global substitution of image: xyz
on a separate line with <img src='xyz'/>
:
text.gsub!(/^image:(.+)$/) { "<img src='#{$1}'/>" }
Why did my Rails find query select all records?
Passing a block to find
changes the behaviour of the method. What ends up happening is it will load all models, then return only those for which the supplied block returns true
, not unlike how Enumerable#find
works.
If you did something like:
MyUserModel.find { |m| [1,2,3].include?(m.id) }
Then you'd have an equivalent version, though this one is way slower since all records must be loaded rather than filtering at the database level.
Generally you'd want to write this as:
MyUserModel.where(id: [ 1, 2, 3 ]).each do |model|
# ...
end
Related Topics
Best Way to Use Twitter Bootstrap Icons as Links in Ruby on Rails 3
Twitter Bootstrap Displays Button with Greyed Text
R Statistical Package Gem for a Rails Application
Rails/Ruby Error When Creating Database: Unable to Load the Eventmachine C Extension
Can One Yaml Object Refer to Another
Creating a Setter Method That Takes Extra Arguments in Ruby
Version Sort (With Alphas, Betas, etc.) in Ruby
Converting a Unique Seed String into a Random, Yet Deterministic, Float Value in Ruby
Rails Cannot Load Such File -- MySQL2/Mysql2 (Loaderror)
How to Decode Q-Encoded Strings in Ruby
Can't Run Bundle Update on Windows
Time Gt Query Not Working with Mongoid and Ruby on Rails
Optional Parens in Ruby for Method with Uppercase Start Letter
How to Use Same Browser Window for Automated Test Using Selenium-Webdriver (Ruby)
How to Get a Selenium/Ruby Bot to Wait Before Performing an Action