Hash condition in where method Ruby on Rails - ruby-on-rails

I have an issue attempting to perform this call:
animals = pet_animals.where(
:healthy => true,
:owned => false,
:bought <= bought_date
)
This line is causing errors. :bought <= bought_date
How can I perform this comparison?

When you are running one an up-to-date version of Ruby and Ruby on Rails then you can use in infinite range to describe the condition:
animals = pet_animals.where(
healthy: true, owned: false, bought: (..bought_date)
)
For version for Ruby below Ruby 2.6 or prior Rails 6.0 you need to use the array syntax to describe such conditions:
animals = pet_animals.where(healthy: true, owned: false)
.where("bought <= ?", bought_date)
Btw I switched to the newer hash syntax because it is more common nowadays than the old hash rocket (=>) in cases like these.

Related

Relation passed to #or must be structurally compatible from Rails 5.1 to 5.2

my app is broken after the update of Rails fom 5.1 to 5.2
The error is: Relation passed to #or must be structurally compatible, Incompatible values: [:create_with]): and I cannot understand what is wrong.
The issue come from this scope
scope :publication, -> do
where.not(type: 'Content::Teaser').
where.not(home_position: nil).
or(
Content::Teaser.where(
id: Content::Teaser.select(:id).joins(:content).where(content: Content.publication)
)
)
end
Why this error?
# scope should only really be used for one-liners as its just syntactic sugar
# and hurts the readability of your code
def self.publication
where.not(type: 'Content::Teaser').
where.not(home_position: nil).or(
# provided that Content.publication is a scope
Content::Teaser.joins(:content).where(Content.publication)
)
)
end

paper trail editing previous object

I've been using paper_trail 3.0 for a long time and been happily editing previous versions with the following code;
# Update a level version with a new date or costing
def update_version(version_id, data)
version = PaperTrail::Version.find(version_id) # Find the version
hash = YAML.load(version.object) # Convert object to a hash
hash["from_date"] = data[:from_date] unless data[:from_date].nil? # Update date
hash["cost_cents"] = data[:cost_cents] unless data[:cost_cents].nil? # Update cost
version.object = YAML.dump(hash) # Convert hash back into YAML
version.save # Save the version
end
After upgrading to paper trail 4.0 this has stopped working as I can no longer do a version.object call. Is there a way to keep editing previous versions easily with version 4.0 of a paper trail and future versions of paper trail?
Update
After looking into it further I think the update_version may work but how it's creating the versions is different in paper_trail 4.0
This is how I create the version
has_paper_trail :only => [:from_date],
:if => Proc.new { |level|
level.versions.count == 0 || level.versions.item.first != nil && (level.versions.first.item.from_date.nil? || level.from_date > level.versions.first.item.from_date)
}
After putting a byebug in here I found that level.versions.item is nil!
Update
Within my tests which are working in paper_trail 3.x but not in 4.x, I use update_attributes. I've noticed that between the two versions paper_trail treats the update_attributes differently. The ': if' rule above is run before update_attributes in 3.x, but in 4.x it runs after. Which means my check on the 'from_date' doesn't work. Therefore it's not creating another version.
Answer
I have to move my Proc into the only section like so;
has_paper_trail :only => [:from_date => Proc.new { |level|
level.versions.count == 0 || level.versions.first.item != nil && (level.versions.first.item.from_date.nil? || level.from_date > level.versions.first.item.from_date)
}
]

Ember model only loads last record

I'm trying to reproduce Railscasts 410 example (called Raffler), changing the setup for last versions and to match my habits:
Ember 1.0.0-rc.6
Rails 4.0.0
Mongoid master (4.0)
Haml 4
Emblem 0.3.0
In this example project, we create a simple model Entry that calls a small Rails Rest API.
Everything works as expected, except that calling Raffler.Entry.find() to get all entries only loads the last record.
Here is my model :
Raffler.Entry = DS.Model.extend
name: DS.attr('string')
winner: DS.attr('boolean')
My store :
DS.RESTAdapter.configure('plurals', entry: 'entries')
Raffler.Store = DS.Store.extend
revision: 12
adapter: DS.RESTAdapter.create()
When calling Raffler.Entry.find() there's an AJAX request on http://localhost:3000/entries and all records are returned (so I don't think the problem is server side) :
{"entries":[{"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true},{"id":{"$oid":"51e5b35b492cd4d286000002"},"name":"Bar","winner":false},{"id":{"$oid":"51e5b384492cd4d286000003"},"name":"Baz","winner":true}]}
But only the last of these records is really loaded in the model.
Here in the JS console :
e=Raffler.Entry.find()
e.toArray().length
=> 1
e.objectAt(0).get('name')
=> "Baz" (always the last one)
e.objectAt(1)
=> undefined
I've finally found the cause of the problem (thanks to this question): it was because, by default, Mongoid returns JSON with id in the format {"id":{"$oid":"51e5b35b492cd4d286000001"}, that Ember does not seem to understand.
By adding this serializer on my Rails Entry model:
class EntrySerializer < ActiveModel::Serializer
attributes :id, :name, :winner
def id
object._id.to_s
end
end
API request now responds this (note there's no $oid anymore):
{"entries":[{"id":"51e5b35b492cd4d286000001","name":"Foo","winner":true},{"id":"51e5b35b492cd4d286000002","name":"Bar","winner":false},{"id":"51e5b384492cd4d286000003","name":"Baz","winner":true}]}
and Ember now loads all records :
Raffler.Entry.find().toArray().length
=> 3
EDIT: Note that this is a Mongoid 4 specific issue since the $oid notation wasn't used in earlier versions. Here is a test with an existing Rails 3.2 / Mongoid 3.0 app :
1.9.3-p194 :006 > Mongoid::VERSION
=> "3.0.23"
1.9.3-p194 :007 > Node.first.id.as_json
=> "507521e68df996381b00151b"
Now with my Ember test under Rails 4 / Mongoid 4 :
2.0.0-p247 :007 > Mongoid::VERSION
=> "4.0.0"
2.0.0-p247 :008 > Entry.first.id.as_json
=> {"$oid"=>"51e5b35b492cd4d286000001"}
I've added the mongoid tag to my question.
The Serializer solution works well but it means creating a serializer for every single Mongoid model...just to return to Mongoid 3 behavior...not that clean...
You have posted that Raffler.Entry.find() returns this :
{"entries":[{"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true},{"id": {"$oid":"51e5b35b492cd4d286000002"},"name":"Bar","winner":false},{"id":{"$oid":"51e5b384492cd4d286000003"},"name":"Baz","winner":true}]}
than :
e=Raffler.Entry.find()
e.entries.length
=> 3
e.entries[0]
=> {"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true}
e.entries[0].name
=> "Foo"
Whats the problem?

Rails 3.1: 'where' with multiple conditions and 'not nil' verification

I want to find records with multiple conditions and this is my code:
#calhappybd = Client.where(:user_id => current_user.id, "birth IS NOT NULL")
I'm trying to do this with squeel-gem, but when I try to use multiple conditions (where{(cond1)(cond2)}), but my current_user.id defined as simple string-data.
With squeel, you should be able to do something like
#calhappybd = Client.where{(user_id == current_user.id) & (birth != nil)}
Let know if you get the same error again...
UPDATED:
Modified the conditions above. Note the single ampersand and double equals. That works for me..
My configuration:
rails 3.1.0.rc6
squeel 0.8.8

Test if a word is singular or plural in Ruby on Rails

Quick question.
How can I test a word to see if it is singular or plural?
I'd really like:
test_singularity('word') # => true
test_singularity('words') # => false
I bet rails is capable!
Thanks.
Well in rails, you can do a string#singularize|#pluralize comparison to return a true or false value.
But I would think due to the nature of language itself, this might need some backup to do be completely accurate.
You could do something like this
def test_singularity(str)
str.pluralize != str && str.singularize == str
end
But to see how accurate, I ran a quick set of words.
%w(word words rail rails dress dresses).each do |v|
puts "#{v} : #{test_singularity(v)}"
end
word : true
words : false
rail : true
rails : false
dress : false
dresses : false
I was a little surprised actually, since 'dress' does get pluralized properly, but when it goes through the #singularize it runs into a bit of a snag.
'dress'.pluralize # => dresses
'dress'.singularize # => dres
Most of the times i never test for singularity or plural, i just convert it to the singular or plural form i require.
In Rails 2.3.x this was possible, writing something like this
plural_form = org_word.singularize.pluralize
singular_form = org_word.pluralize.singularize
Working further on this, a working function is easy to supply:
require 'active_support'
def is_singular?(str)
str.pluralize.singularize == str
end
%w(word words rail rails dress dresses).each do |v|
puts "#{v} : #{is_singular?(v)}"
end
which gives the following output:
word : true
words : false
rail : true
rails : false
dress : true
dresses : false
In Rails 4, with the given words, it is now much easier. You can just do
plural_form = org_word.pluralize
singular_form = org_word.singularize
and thus the function becomes much easier as well:
require 'active_support'
def is_singular?(str)
str.singularize == str
end
Neither ruby nor rails come with a specific method for testing for "plurality" on words.
As nowk said, the most you can do is implement them yourself, comparing with word.pluralize and word.singularize. This will give you a quick-and-cheap-and-generally-good way of testing. It will fail some times, though.
If you need more precision, you will need to use the Ruby Linguistics gem, which can deal with dress and dresses properly (but it's heavier).

Resources