What Is the Point of Object#Presence in Rails

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



Leave a reply



Submit