Logic to an if statement - ruby-on-rails

I have the following logic in my view to choose which avatar picture to show depending on whether a persons profile is present
<% if #profile %>
<%= image_tag(#profile.avatar_url(:thumb)) %>
<% else %>
<%= image_tag(default_image_url) %>
<% end %>
Helper method
def default_image_url
hash = Digest::MD5.hexdigest(current_user.email)
"https://secure.gravatar.com/avatar/#{hash}?s=100&d=mm"
end
This works fine when someone has not created a profile, but when they do and still want to use their Gravatar this logic fails as my if condition then needs to be if
<% if #profile.avatar? %>
<%= image_tag(#profile.avatar_url(:thumb)) %>
<% else %>
<%= image_tag(default_image_url) %>
<% end %>
At the moment when a profile is created with no image uploaded by the user, there is no image displayed at all.
How can I cover all scenarios?
Edit
I'm in the process of trying
<% unless #profile || #profile.avatar %>

A bit of refactoring starting from #ArieShaw's answer:
Helper
def profile_image_url
#profile.try(:avatar?) ? #profile.avatar_url(:thumb) : default_image_url
end
View
<%= image_tag profile_image_url %>

You may use Object#try:
<% if #profile.try(:avatar?) %>
<%= image_tag(#profile.avatar_url(:thumb)) %>
<% else %>
<%= image_tag(default_image_url) %>
<% end %>

Related

Can I query against the DEVISE current_user helper in my application menu?

The problem is, In the menu of my app I want to check if the current user has a book. If they do I will show a link to the edit book path, if not, I will show a link to the create book path.
<% if current_user.book? %>
<% else %>
<% end %>
Yes, you should be able to access current_user from any controller. But always make sure you handle if current_user returns nil.
You can use a try or safe navigation.
<% if current_user.try(:book?) %>
<% else %>
<% end %>
Or
<% if current_user&.book? %>
<% else %>
<% end %>

How to display the creation date of a badge earning with merit gem

I'm trying to find a way to display in a View the badge & the "granted_at" record. It would render (in the view) :
<% #profil.badges.each do |badge| %>
<%= image_tag (badge.custom_fields[:image]), badge.granted_at %>
<% end %>
Should I enable the MeritObserver to get this on the view ? Or there is a simpler solution?
(I'm on Rails 5)
EDIT
Thanks to TuteC, we have an answer :
<% #profil.sash.badges_sashes.each do |badge_sash| %>
<%= image_tag (badge_sash.badge.custom_fields[:image]) %><%= badge_sash.created_at %>
<% end %>
You've got to go through sash and badges_sashes relations:
<% #profil.sash.badges_sashes.each do |badge_sash| %>
<%= image_tag(badge_sash.badge.custom_fields[:image]), badge_sash.created_at %>
<% end %>
You can read about merit internals in https://github.com/merit-gem/merit/wiki/General-merit-workflow.

Adding user's photo to contest, call method with link_to

I came from a JS background so Rails is weird to me. I currently have a show.html.erb for the contest model:
<h1>Contest name: <%= #contest.name %></h1>
<h2>Contest criteria: <%= #contest.criteria %></h2>
<h3>Photos: </h3>
<%= link_to "Enter Contest", "#" %>
<% #contest.photos.each do |photo| %>
<%= image_tag("#{photo}") %>
<% end %>
With the link_to I'm trying to render all photos that belongs to the current_user and pick one of them to assign it to the current contest. The params passing seems all so mysterious to me. Can you guys point me in the right direction of how I should tackle this problem? Thanks
What I understand you need to select an image from list of images and pass the id. So, try this
<%= label_tag "Enter Contest" %>
<% #contest.photos.each do |photo| %>
<%= link_to (image_tag("#{some photo path}")), some_controller_method_path(:photo_id => photo.id) %>
<% end %>
And in controller you can use params[:photo_id]

Conditional line spacing in ERb partials

This is the code for an address partial I just wrote. People might put single line addresses in either street line, company name is optional, etc... It works exactly how I want it to, but I know that checking each variable twice is ugly and terrible.
<%= "#{a.name}" unless a.name.blank? %>
<% unless a.name.blank? %> <br> <% end %>
<%= "#{a.company_name}" unless a.company_name.blank? %>
<% unless a.company_name.blank? %> <br> <% end %>
<%= "#{a.street_1}" unless a.street_1.blank? %>
<% unless a.street_1.blank? %> <br> <% end %>
<%= "#{a.street_2}" unless a.street_2.blank? %>
<% unless a.street_2.blank? %> <br> <% end %>
<%= "#{a.city}, #{a.state} #{a.zip}" %>
So, my gratuitous use of unless aside, how should I be putting in a conditional line break?
Update:
As discussed below, it is dangerous to use .html_safe on user input. If you do use a helper method as suggested below, you must also sanitize all user input on the way into the database. I've rewritten the code above as:
<% unless a.name.blank? %>
<%= a.name %>
<br>
<% end %>
<% unless a.company_name.blank? %>
<%= a.company_name %>
<br>
<% end %>
<% unless a.street_1.blank? %>
<%= a.street_1 %>
<br>
<% end %>
<% unless a.street_2.blank? %>
<%= a.street_2 %>
<br>
<% end %>
<%= "#{a.city}, #{a.state}" %> <%= a.zip %>
The redundant checking was just me overcomplicating things. I'd strongly recommend against using .html_safe in a situation like this, since you create new problems for yourself: sanitizing the input, and remembering which fields are safe. Better to not override the sensible protection Rails provides.
There are many, many ways to go about cleaning it up, but a helper would be appropriate here:
module ApplicationHelper
def format_address(a)
top = [a.name, a.company_name, a.street_1, a.street_2]
top.reject! {|s| s.blank?} # remove null and empty values
"#{top.join('<br/>')}#{a.city}, #{a.state} #{a.zip}".html_safe
end
end
Then in your view:
<%= format_address(a) %>

Creating multiple objects in a form Rails

So I have an interesting problem I'm working on. I am trying to create multiple objects of the same model in one view. I would like to display all the possible objects in my view, check boxes to select which ones to create, then submit and create all the corresponding objects.
Now the objects to select are gotten using an API request and returned in JSON format. The JSON is then displayed on the view for the user to select, then an array containing all the selected objects is sent back to the controller for creation.
Here is the relevant code that I've tried so far.
objects_controller.rb
def new
#possible_objects = <api call to get objs>
#objects = []
end
def create
params[:objects].each do |obj|
# create and save obj
end
end
objects/new.html.erb
<% form_for #objects do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag(api_obj["name"])%>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
This is definitely not the right approach, as the form will not accept an empty array as a parameter. I'm not sure where else to go with this, any pointers in the right direction would be great. Thanks.
Thanks to MrYoshiji for pointing me in the right direction, this is what ended up working
objects_controller.rb
def
#possible_objects = <api call to get objs>
end
def create
params[:objects].each do |object|
new_obj = Object_Model.new( <params> )
new_obj.save
if !new_obj.save
redirect_to <path>, alert: new_obj.errors.full_messages and return
end
end
redirect_to <path>, notice: 'Successfully created.'
end
objects/new.html.erb
<%= form_tag objects_path(method: :post) do %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[]', api_obj %>
<%= possible_object["name"] %>
<% end %>
<%= submit_tag 'Create'%>
<% end %>
Can you try the following?
# view
<% form_tag my_objects_path(method: :post) do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[names][]', api_obj["name"] %>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
# controller
def create
params[:objects][:names].each do |obj_name|
YourModelForObject.create(name: obj_name)
end
end
See this comment on the documentation of check_box_tag: http://apidock.com/rails/ActionView/Helpers/FormTagHelper/check_box_tag#64-Pass-id-collections-with-check-box-tags

Resources