How to avoid same instance variables for footer - ruby-on-rails

I have a footer in my rails application that shows all recent posts and categories produced by two instances variables in the welcome_controller.rb
But then if i go to another section that has a different controller responsible i get an error as the #posts and #categories instance variables are not there to loop through and list the latest posts and categories.
welcome_controller.rb (code extract)
#categories = Category.all
#posts = Post.order("created_at DESC")
_footer.html
<div class="row footer-black">
<div class="large-3 columns text-left">
<h4>Categories</h4>
<ul>
<% #categories.each do |c| %>
<% unless c.header? %>
<% if c.restriction %>
<% if check_for_free_questions_in_restricted_category(c) %>
<li> <%= link_to c.title, category_random_free_question_path(c),'data-no-turbolink' => true %> </li>
<% else %>
<li> <%= link_to c.title, new_subscription_path,'data-no-turbolink' => true %> </li>
<% end %>
<% else %>
<li> <%= link_to c.title, category_random_question_path(c),'data-no-turbolink' => true %> </li>
<% end %>
<% end %>
<% end %>
</ul>
</div>
<div class="large-5 columns text-left">
<h4>Latest Posts</h4>
<ul>
<% #posts.each do |p| %>
<li> <%= link_to truncate(p.title, length:70), blog_post_path(p) %> </li>
<% end %>
</ul>
</div>
<div class="large-4 columns text-left social-links">
<h4>Social</h4>
<a href="#">
<i class="fa fa-facebook-square fa-2x"></i>
</a>
<a href="#">
<i class="fa fa-twitter-square fa-2x"></i>
</a>
<a href="#">
<i class="fa fa-google-plus-square fa-2x"></i>
</a>
</div>
</div>
is there a way to show categories and posts in footer without instantiating same variables over and over again?

The short answer is 'no'. Every variable must be instantiated (initialized) before it can be used (in this case, in your view).
Now, there are some more efficient ways of instantiating these variables than writing:
#categories = Category.all
#posts = Post.order("created_at DESC")
in multiple controllers. But, that's a different question. If you're interested in that, then ask a new question or refine this one.

Related

Notifications ruby on rails

Currently I have a notification system when a patients fills out a form they request a signature from a doctor. The doctor gets notified successfully. But what I am looking for is when the doctor gets the notification they can click on it (link_to) and be redirected automatically to the form.
<% if #notifications.count > 0 %>
<ul>
<% #notifications.each do |notification| %>
<li>
<span class="notification-title"><%= notification.title %></span>
<span class="notification-message"><%= notification.message %></span>
<span class="notification-time"><%= notification.created_at.strftime("%B %e at %l:%m%P") %></span>
</li>
<% end %>
</ul>
<div class="notifications-preview-footer">
<%= link_to "See All", notifications_path %>
</div>
<% else %>
<ul>
<li>No Notifications</li>
</ul>
<% end %>
I changed your title span with link_to sample, so if the title clicked then it will go to notification show page
<% if #notifications.count > 0 %>
<ul>
<% #notifications.each do |notification| %>
<li>
<%= link_to <span class="notification-title"><%= notification.title %></span>, notification_path(notification) %>
<span class="notification-message"><%= notification.message %></span>
<span class="notification-time"><%= notification.created_at.strftime("%B %e at %l:%m%P") %></span>
</li>
<% end %>
</ul>
<div class="notifications-preview-footer">
<%= link_to "See All", notifications_path %>
</div>
<% else %>
<ul>
<li>No Notifications</li>
</ul>
<% end %>
A lot of unknowns here, first you routes.rb file needs to have the routes defined to allow this say maybe
# config/routes.rb
resources: notifications
Then in you need to define the controller actions for a view maybe show/edit?
# notifications_controller.rb
class NotificationsController < ApplicationController
def show
#notification = Notification.find(params[:id])
end
end
Then you could modify you view like above to allow a link to each notification
<% #notifications.each do |notification| %>
<li>
<%= link_to <span class="notification-title"><%= notification.title %></span>, notification_path(notification) %>
<span class="notification-message"><%= notification.message %></span>
<span class="notification-time"><%= notification.created_at.strftime("%B %e at %l:%m%P") %></span>
</li>
<% end %>
This may get you what you're looking for.

Best way to show empty lists in Rails

I have been working to follow the best practices in Rails in order to save time in the future.
I am displaying all terms in a view which has more than 0 results.
<% #terms.each do |t| %>
<li class="media">
<div class="media-body">
<div class="media-heading text-semibold"><%= link_to "#{t.name}", authenticated_root_path %></div>
<span class="text-muted"><%= link_to 'Settings', edit_account_term_path(#account, t) %></span>
</div>
</li>
<% end %>
What is the best way to display a different view if the term count is zero? I could do something like a simple if statement in the view doing a count but that seems cluttered. Any suggestions?
How about this:
<% #terms.each do |t| %>
<li class="media">
<div class="media-body">
<div class="media-heading text-semibold"><%= link_to "#{t.name}", authenticated_root_path %></div>
<span class="text-muted"><%= link_to 'Settings', edit_account_term_path(#account, t) %></span>
</div>
</li>
<% end.empty? and begin %>
<li class="media">
<!-- nothing to see -->
</li>
<% end %>
You can also move the code to a partial.
<%= render(:partial => 'terms', :collection => #terms) || 'There are no terms' %>
The partial:
<li class="media">
<div class="media-body">
<div class="media-heading text-semibold"><%= link_to "#{term.name}", authenticated_root_path %></div>
<span class="text-muted"><%= link_to 'Settings', edit_account_term_path(#account, term) %></span>
</div>
</li>
</li>

undefined method `count' for nil:NilClass rails

I am trying to have a photo upload section in my room listing. when I try to click on the photos I get this error
undefined method 'count' for nil:NilClass rails <% if #photos.count > 0 %> .
I have added a photo_upload.html.erb page and a _room_menu partial but still I get the error.
here's my code:
photos_controller.rb
class PhotosController < ApplicationController
def create
#room = Room.find(params[:room_id])
if params[:images]
params[:images].each do |img|
#room.photos.create(image:img)
end
#photos = #room.photos
redirect_back(fallback_location:request.referer, notice: "Saved...")
end
end
end
**views/rooms/photo_upload.html.erb**
<div class="row">
<div class="col-md-3">
<%= render 'room_menu' %>
</div>
<div class="col-md-9">
<div class="panel panel-default">
<div class="panel-heading">
Photos
</div>
<div class="panel-body">
<div class="container">
<div class="row">
<div class="col-md-offset-3 col-md-6">
<!-- PHOTOS UPLOAD GOES HERE -->
<%= form_for #room, url: room_photos_path(#room), method: 'post', html: {multipart: true} do |f| %>
<div class="row">
<div class="form-group">
<span class="btn btn-default btn-file text-babu">
<i class="fa fa-cloud-upload" aria-hidden="true"></i> Select Photos
<%= file_field_tag "images[]", type: :file, multiple: true %>
</span>
</div>
</div>
<div class="text-center">
<%= f.submit "Add Photos", class: "btn btn-form" %>
</div>
<% end %>
</div>
</div>
<div id="photos"><%= render 'photos/photos_list' %></div>
</div>
</div>
</div>
</div>
</div>
views/rooms/_room_menu.html.erb
<ul class="sidebar-list">
<li class="sidebar-item">
<%= link_to "Listing", listing_room_path, class: "sidebar-link active" %>
<span class="pull-right text-babu"><i class="fa fa-check"></i></span>
</li>
<li class="sidebar-item">
<%= link_to "Pricing", pricing_room_path, class: "sidebar-link active" %>
<% if !#room.price.blank? %>
<span class="pull-right text-babu"><i class="fa fa-check"></i></span>
<% end %>
</li>
<li class="sidebar-item">
<%= link_to "Description", description_room_path, class: "sidebar-link active" %>
<% if !#room.listing_nam.blank? %>
<span class="pull-right text-babu"><i class="fa fa-check"></i></span>
<% end %>
</li>
<li class="sidebar-item">
<%= link_to "Photos", photo_upload_room_path, class: "sidebar-link active" %>
<% if !#room.photos.blank? %>
<span id="photo_check" class="pull-right text-babu"><i class="fa fa-check"></i></span>
<% end %>
</li>
<li class="sidebar-item">
<%= link_to "Amenities", amenities_room_path, class: "sidebar-link active" %>
<span class="pull-right text-babu"><i class="fa fa-check"></i></span>
</li>
<li class="sidebar-item">
<%= link_to "Location", location_room_path, class: "sidebar-link active" %>
<% if !#room.address.blank? %>
<span class="pull-right text-babu"><i class="fa fa-check"></i></span>
<% end %>
</li>
</ul>
<hr/>
You can't call .count on a nil. #photos must be instantiated first. You controller doesn't appear to instantiate #photos at all. I can't see where else in your code you're calling #photos but where it's getting called, the instance variable has not yet be defined. Your controller create method only shows it happens if params[:images] is present, if otherwise it will be nil.
Try to instantiate #photos outside the if block.
def create
#room = Room.find(params[:room_id])
#photos = #room.photos
if params[:images]
params[:images].each do |img|
#room.photos.create(image: img)
end
redirect_back(fallback_location:request.referer, notice: "Saved...")
end
end
UPDATE: Ruby 2.3+ you can use safe navigation with & :
def create
#room = Room.find(params[:room_id])
params[:images]&.each{|img| #room.photos.create(image: img)}
redirect_back(fallback_location: request.referer, notice: "Saved...")
end
Or why bother using separate #photos in view when you should be able to just call #room.photos in it's place.
Instead of calling .count as your conditional in the view, use #room.photos.present?
One more suggestion is to prefer to use positive if case. so change
if !#room.photos.blank?
# better to use this below
if #room.photos.present?
Also, one would assume before a create action, you need a new action in your controller where one would expect #photos to be defined if it really needs be isolated from #room.photos. This is standard MVC in rails, but not sure if you've posted all of your code correctly so I'm guessing here.
The people above have already given great explanations as to why you can't call a method on a nil class. In addition, maybe the following code will help in your situation:
<% if !#photos.nil? && #photos.count > 0 %>
<% if #photos.count > 0 %>
If this fails with an error 'undefined method for nil class', then it means #photos is nil, and you therefore can't perform any methods on it. Where are you calling it? You've not included it in your code.
When you click on the link, look at your server logs and it will tell you which controller action you are hitting. Whichever action you're hitting, is where you'll need to define #photos.
If it is photos#create (the controller action you listed above) then it means that #room.photos is nil. That's unlikely, as it would almost certainly return an empty active record relation if anything, so your problem is not defining #photos in the controller and action you're using at that time.

Rails view returning database field after loop

In my view I do this:
<ul class="list-group">
<%= JSON.parse(current_printer.stripe_managed_account.fields_needed).each do |f| %>
<li class="list-group-item">
<%= f.gsub!(/[._]/, ' ') %>
</li>
<% end %>
</ul>
It lists everything out like it should, but then at the end it returns the value of current_printer.stripe_managed_account.fields_needed. I'm not sure why it does this, or how to prevent it from doing this.
This is a screenshot:
Replace <%= %>, on your each line by <% %>.
Because <%= #your each %> is same that : <% puts #your each %>.
Try this:
<ul class="list-group">
<% JSON.parse(current_printer.stripe_managed_account.fields_needed).each do |f| %>
<li class="list-group-item">
<%= f.gsub!(/[._]/, ' ') %>
</li>
<% end %>
</ul>
Thanks #vee

Kaminari not limiting collection in Spree

For some reason Kaminari is not limiting child objects on the parent show view.
Can see the pagination links but the collection does not get limited.
What am I doing wrong?
View -
<% if #handbag.microposts.any? %>
<h3>Posts (<%= #handbag.microposts.count %>)</h3>
<div class="row">
<div class="col-md-8">
<ol class="microposts">
<% #handbag.microposts.each do |micropost| %>
<li id="micropost-<%= micropost.id %>">
<span class="user"><%= micropost.user.email %></span>
<span class="content"><%= micropost.content %></span>
<%= image_tag micropost.picture.url if micropost.picture? %>
<span class="timestamp">
Added <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
</li>
<% end %>
</ol>
<%= paginate #microposts %>
Controller -
def show
#handbag = Spree::Handbag.find(params[:id])
#microposts = #handbag.microposts.page(params[:page] || 1).per(10)
end
Thanks for any help.
You're looping through #handbag.microposts, which is the entire collection, instead of #microposts, which is the paginated collection.
So just change #handbag.microposts.each to #microposts.each

Resources