What is the point of Object#presence in Rails?
Here's the point:
''.presence
# => nil
so if params[:state] == ''
:
region = params[:state].presence || 'US'
# => 'US'
region = params[:state] || 'US'
# => ''
What's more, it works in similar way (that is, returns nil
if object is 'empty') on every object that responds to empty?
method, for example:
[].presence
# => nil
Here's the documentation, for reference:
http://api.rubyonrails.org/classes/Object.html#method-i-presence
Rspec, stubbing the presence of an object in a Rails application controller
I'm not sure you can easily stub a member in rspec. You can either set the member with a value, or (preferably) refactor your code to read the value from a getter rather than a member:
def venue
@venue ||= Venue.friendly.find(params[:venue_id])
end
def location_details
@venue_information ||= {
opening_times: venue.facility_with_opening_hours.any? ? venue.facility_with_opening_hours.first.opening_times_for_week(Date.today) : '',
location: {address1: venue.address1,
address2: venue.address2,
town: venue.town,
county: venue.county,
postcode: venue.postcode},
contact: {email: venue.email,
telephone: venue.telephone},
social: {facebook: venue.facebook,
twitter: venue.twitter}
}
end
How to validate presence of at least one nested object?
One of the options is to use custom validation:
validate :questions_count
private
# or something more explicit, like `at_least_one_question` (credits to @MrYoshiji)
def questions_count
errors.add(
:base,
'You can not save a survey without questions. Add at least one question'
) if questions.none?
end
Basically, the validation will be fired every time you create or "touch" (update) the survey
object, and it will fail, if survey
will not have at least one question
associated.
How to trigger conditional based on object presence on object's attribute route?
Did you try:
<% if @challenges.none?{ |challenge| challenge.categorization } %>
You have no challenges for this category.
<% end %>
Better solution:
# assuming that the foreign key is categorization_id
@challenges.any?(&:categorization_id)
Equivalent of .presence in Python
In Python, you can achieve this by doing the following, assuming params
is a dict
:
state = params.get('state')
country = params.get('country')
region = 'US' if (state and country) else None
The method dict.get(key)
will return the value associated to the key that has been passed. If no such key exists, it returns None
.
If you need to replace the empty values with actual empty strings, you may do this instead:
state = params.get('state', '')
country = params.get('country', '')
region = 'US' if (state and country) else ''
Overall, the "Pythonic" way of doing this is to use a Form:
class Address(Model):
state = ...
country = ...
region = ...
AddressForm = modelform_factory(Address)
#inside view
def view(request):
if request.method == 'POST':
form = AddressForm(request.POST, request.FILES)
if form.is_valid():
address = form.save(commit=False)
address.region = 'US' if address.state and address.country
address.save()
By creating a custom AddressForm class you can do this processing automatically on the instance before saving it. This is the precise role of Form classes.
Rails 4: Difference between validates presence on id or association
Investigating further, I found that the 'presence' validator resolves to 'add_on_blank':
http://apidock.com/rails/ActiveModel/Errors/add_on_blank
def add_on_blank(attributes, options = {})
Array(attributes).each do |attribute|
value = @base.send(:read_attribute_for_validation, attribute)
add(attribute, :blank, options) if value.blank?
end
end
This does what it says: adds a validation error if the property in question is blank?
This means it's simply an existence check. So if I validate an id, that id has to exist. That means:
topping.pancake = Pancake.new
topping.valid?
would return false. However:
topping.pancake_id = -12
topping.valid?
would return true. On the other hand, if I validate the object the exact opposite would be true. Unless -12 is a valid index, in which case ActiveRecord would automatically load it from the database on receipt of the 'pancake' message.
Moving on to my issue, further investigation showed that blank?
delegates to empty?
, and indeed someone had defined empty?
on the pancake, returning true if there are no toppings.
Culprit found, and something about Rails learned.
How convert an object presence into an integer?
Try this
@count = @product.possible_loans.count + (@product.current_loan.present? ? 1 : 0)
Related Topics
After Installing a Gem Within a Script, How to Load the Gem
Chef and Erb Templates. How to Use Boolean Code Blocks
Get Jekyll Configuration Inside Plugin
Best Way to Work with Large Amounts of CSV Data Quickly
No Source for Ruby-2.0.0-P451 Provided with Debugger-Ruby_Core_Source Gem
Native Extensions Fallback to Pure Ruby If Not Supported on Gem Install
Discriminate First and Last Element in Each
How to Deal with Ruby 2.1.2 Memory Leaks
Examples of 'Things' That Are Not Objects in Ruby
Marking an Unused Block Variable
How to Do a Left Outer Join Using Rails Activerecord
Ruby: Eval with String Interpolation
Split Array Up into N-Groups of M Size