In which controller should I place elements that persist throughout the application? - ruby-on-rails

Everything after #posts should persist throughout the application (Like the left sidebar you find on Facebook).
def index
#title = "Posts"
default_order = "content_changed_at DESC"
params[:order_by] ||= default_order
#posts = current_user.subscribed_posts.paginate(:page => params[:page],
:per_page => 5,
:order => params[:order_by])
#subscribed_tags = current_user.subscribed_tags
#recent_posts = current_user.posts.limit(5).order("created_at DESC")
#tags= Tag.limit(20).order("ID asc")
#user = current_user
end
views/layout/_sidebar.html.erb:
<div class="user-profile">
<% avatar = image_tag(current_user.avatar.url(:thumb), :class => "authenticated-avatar") %>
<%= link_to avatar, "/users/#{current_user.id}" %>
<%= link_to "#{current_user.username}", "/users/#{current_user.id}", :class => "authenticated-username" %>
</div>
<%= form_for(#user, :remote => true) do |f| %>
<div class="field">
<%= f.label :subscribed_tag_names %><br />
<%= f.autocomplete_field :subscribed_tag_names, autocomplete_tag_name_posts_path, :"data-delimiter" => ' ', :class => "autocomplete_field" %>
</div>
<div class="actions">
<%= f.submit :class => "user_subscribed_tag_names_submit" %>
</div>
<% end %>
<div class="user-subscribed_tags">
<% #subscribed_tags.each do |subscribed_tag| %>
<%= link_to "#{subscribed_tag.name}(#{subscribed_tag.posts.count})", unsubscribe_tags_path(:unsubscribed_tag_name => subscribed_tag.name) %>
<% end %>
</div>
<div class="user-recent-posts">
<h4>Recent Posts</h4>
<ul>
<% #recent_posts.each do |recent_post| %>
<li><%= link_to recent_post.title, recent_post %></li>
<% end %>
</ul>
</div>
<div class="top-tags">
<% #tags.each do |tag| %>
<span class="tag-name"><%= tag.name %></span>
<span class="tag-count"><%= tag.posts.count %></span>
<% end %>
</div>
<% end %>
Where should I place the code in the controller if I want them to persist throughout the application? (I would like to see some example code if possible).

If it persists throughout the application, i.e. for every actions of all controllers, you might place it in a before_filter in the application controller.
Add a before_filter to the application controller as :
before_filter :find_recent_posts_and_tags
And define it (as private) :
private
def find_recent_posts_and_tags
# define your instance variables
end
More about filters here and here.

Related

Rails: Ransack and will_paginate (undefined method 'total_pages' error)

I'm attempting to use will_paginate for a search with Ransack for pagination, and I'm getting the following error: undefined method `total_pages' for #
I'm not sure what it is that I'm doing incorrectly here and have tried a number of possible solutions with no luck. Is it possible to use these together and what am I doing incorrectly here? Thanks.
coin_controller.rb
class CoinsController < ApplicationController
load_and_authorize_resource param_method: :question_params
before_action :find_coin, only: [:edit, :update, :destroy ]
before_action :authenticate_user!, except: [:index, :create, :show]
def index
#search = Coin.ransack(params[:q])
#coins = #search.result.paginate(page: params[:page], per_page: params[:per_page])
end
.
.
.
end
index.html.erb
<% provide(:title, "Coins") %>
<% #coins = #coins.sort_by &:currency_name %>
<%= will_paginate #coins %>
<div class="row">
<div class="col-md-8" id="pagination_table">
<% #coins.each do |coin| %>
<% if coin.accepted %>
<ul>
<%= image_tag coin.picture.thumb.url if coin.picture? %>
<%= link_to coin.currency_name, :action => 'show', :id => coin %>
</ul>
<% end %>
<% end %>
<% if can? :edit, Coin %>
<hr><b>Pending Approval</b><hr>
<% #coins.each do |coin| %>
<% if not coin.accepted %>
<ul>
<%= image_tag coin.picture.thumb.url if coin.picture? %>
<%= link_to coin.currency_name, :action => 'show', :id => coin %>
</ul>
<% end %>
<% end %>
<% end %>
</div>
<div class="col-md-3" id="side-bar">
<%= link_to "Submit a New Coin", new_coin_path, class: "btn btn-default" %>
<fieldset class="search-field">
<legend>Search All Coins</legend>
<%= search_form_for #search do |f| %>
<div class="field">
<%= f.label :currency_name_cont, "Search by Name" %>
<%= f.text_field :currency_name_cont %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<div class="field">
<%= f.label "Search by Genre" %><br />
<%= f.collection_check_boxes :genres_id_in_any, Genre.all, :id, :displayname do |b| %>
<div class="collection-check-box">
<%= b.check_box %>
<%= b.label %>
</div>
<% end %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
</fieldset>
</div>
</div>
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
</script>
I also tried using Kaminari and got an identical error.
Try this solution...
Instead of this line
<%= will_paginate #coins %>
To
<%= will_paginate #coins if #coins.present? %>

Ruby on rails Simple Search not displaying results

Hey guys im developing a rails application that stores quotes in a database and then allows you to search through the quotes using a simple search. I have implemented the search form but the results do not appear and I cant figure out why.
controller:
class BasicsController < ApplicationController
def quotations
#quotations = Quotation.all
if params[:search]
#quotations = Quotation.search(params[:search]).order("created_at DESC")
else
#quotations = Quotation.all.order("created_at DESC")
end
if params[:quotation]
#quotation = Quotation.new( params[:quotation] )
if #quotation.save
flash[:notice] = 'Quotation was successfully created.'
#quotation = Quotation.new
end
elsif
#quotation = Quotation.new
end
if params[:sort_by] == "date"
#quotations = Quotation.order(:created_at)
else
#quotations = Quotation.order(:category)
end
end
end
model:
class Quotation < ApplicationRecord
def self.search(search)
where("author_name LIKE ? OR quote LIKE ?", "%#{search}", "%#{search}")
end
end
view:
<%= form_tag basics_quotations_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search], placeholder: "Search Quotations" %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<h3>Quotations</h3>
<ul>
<% for quotation in #quotations %>
<li><%= h quotation.author_name %>: <%= h quotation.quote %></li>
<% end %>
</ul>
<br/>
<% if params[:sort_by] == "date" %>
<%= link_to "Sort by category", :action => :quotations, :sort_by => :category %>
<% else %>
<%= link_to "Sort by date", :action => :quotations, :sort_by => :date %>
<% end %>
<hr/>
<h3>New quotation</h3>
<%= form_for #quotation, :url => { :action => :quotations } do |form| %>
<fieldset>
<legend>Enter details</legend>
<div class="form_row">
<%= form.label :author_name %>
<%= form.text_field :author_name, :size => 20, :maxlength => 40 %>
</div>
<div class="form_row">
<%= form.label :category %>
<% #cats = [] %>
<% Quotation.select('DISTINCT category').map(&:category).each do |element| %>
<% #cats << element %>
<% end %>
<%= form.select(:category,options_for_select([[#cats[0],1],[#cats[1], 2], [#cats[2],3]])) %>
</div>
<div class="form_row">
<%= form.label :new_category%>
<%= form.text_field :category , :size =>20 , :maxlength => 40 %>
</div>
<div class="form_row">
<%= form.label :quote %>
<%= form.text_area :quote, :rows => 2, :cols => 40, :maxlength => 500 %>
</div>
</fieldset>
<p>
<div class="form_row">
<%= form.submit 'Create' %>
</div>
</p>
<% end %>
routes:
Rails.application.routes.draw do
get 'basics/quotations'
resources :quotation, :quotations
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
You've got EVERYTHING in one action, which isn't great. You might want to review some of the simple rails tutorials available.
On the subject of search in particular, note the last four lines of your method...
if params[:sort_by] == "date"
#quotations = Quotation.order(:created_at)
else
#quotations = Quotation.order(:category)
end
So regardless of the results of your seach, you'll replace #quotations at that point with all quotations in either created_at or category order.
It is not wise to place all the stuffs into a single action,your action should be very clear and well defined.But you can achieve what you wanted to do like this.
class BasicsController < ApplicationController
before_action :new_quotation, only:[:search_quotations,:index,:quotations]
def search_quotations
respond_to do |format|
if params[:search]
#quotations = Quotation.search(params[:search]).order("created_at DESC")
else
#quotations = Quotation.all.order("created_at DESC")
end
if params[:sort_by] == "date" && quotations.present?
#quotations = #quotations.order(:created_at)
else
#quotations = #quotations.order(:category)
end
format.js{}
end
end
def quotations
if params[:quotation]
#quotation = Quotation.new( quotation_params)
if #quotation.save
flash[:notice] = 'Quotation was successfully created.'
end
redirect_to root_path
end
end
def index
#quotations = Quotation.all
end
private:
def new_quotation
#quotation = Quotation.new
end
//If you are using rails4 for later version then go for this line.
def quotation_params
params.require(:quotation).permit(:author_name, :quote,:category)
end
end
You need to actually separate the logic into above actions and where 'quotation' action is meant for creating a new quotation and 'seach_quotation' is for searching all the quotations and it should returns js response cause we are going to need this while rendering a partial '_list.html.erb'.
Your view(index.htm.erb) will be looking like this.
<div>
<%= form_tag basics_search_quotations_path, :method => 'get', remote: true do %>
<p>
<%= text_field_tag :search, params[:search], placeholder: "Search Quotations" %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
</div>
#This partial will be used for refreshing the quotations list via remote true feature for searching and sorting.
<div id="quotation_list">
<%= render 'basics/shared/list',{quotations: #quotations} %>
</div>
br/>
<% if params[:sort_by] == "date" %>
<%= link_to "Sort by category", :action => :search_quotations, :sort_by => :category, :remote => true %>
<% else %>
<%= link_to "Sort by date", :action => :search_quotations, :sort_by => :date, :remote => true %>
<% end %>
<hr/>
<h3>New quotation</h3>
<%= form_for #quotation, :url => { :action => "quotations", :controller => "basics" } do |form| %>
<fieldset>
<legend>Enter details</legend>
<div class="form_row">
<%= form.label :author_name %>
<%= form.text_field :author_name, :size => 20, :maxlength => 40 %>
</div>
<div class="form_row">
<%= form.label :category %>
<%= form.select(:category,options_for_select(['Love','Romance','Sadness'])) %>
</div>
<div class="form_row">
<%= form.label :category%>
<%= form.text_field :category , :size =>20 , :maxlength => 40 %>
</div>
<div class="form_row">
<%= form.label :quote %>
<%= form.text_area :quote, :rows => 2, :cols => 40, :maxlength => 500 %>
</div>
</fieldset>
<p>
<div class="form_row">
<%= form.submit 'Create' %>
</div>
</p>
<% end %>
Here is the partial that display the list of Quotations /basics/shared/_list.html.erb
<h3>Quotations</h3>
<ul>
<% for quotation in #quotations %>
<li><%= h quotation.author_name %>: <%= h quotation.quote %></li>
<% end %>
</ul>
Here is the routes you need to add routes.rb
resources :quotation, :quotations
get "basics/search_quotations" => "basics#search_quotations"
post "basics/quotations" => "basics#quotations"
root 'basics#index'
Instead of performing any calculation in views its better to perform it in controller/model if needed.
so instead of this following line in your view
<% #cats = [] %>
<% Quotation.select('DISTINCT category').map(&:category).each do |element| %>
<% #cats << element %>
<% end %>
<%= form.select(:category,options_for_select([[#cats[0],1],[#cats[1], 2], [#cats[2],3]])) %>
You can create an instance variable let's say #categories or something and use it like this
<%= form.select(:category,options_for_select(#categories)) %>
And last but not the least we have to have a search_quotations.js.erb because we are sending ajax request for fetching the search result and returning 'js' response.
$("#quotation_list").html("<%= escape_javascript(render('basics/shared/list', {quotations: #quotations })) %>")

How do I re-populate form fields when validation fails?

This is the erb template:
<div id='recipe-form'>
<% if #recipe.errors %>
<div id='errors'>
<% #recipe.errors.messages.each do |field, messages| %>
<div class='error'>
<div class=field'><%= field %></div>
<div class='messages'>
<ul>
<% messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
</div>
<% end %>
<%= form_for #recipe, :html => {:multipart => true}, :url => '/recipes' do |f| %>
<%= f.label :title, 'title' %>
<%= f.text_field :title %>
<div id="photo-upload">
<%= file_field :photo0, :image, :id => 0 %>
</div>
<div id='existing-photos'>
<% recipe.photos.each do |photo| %>
<div id='<%= photo.id %>'>
<img src='<%= photo.image.url(:thumb) %>' />
<ul>
<li>
<%= link_to 'delete',
recipe_photo_url(
:recipe_id => #recipe.slug,
:id => photo.id
),
:method => :delete,
:remote => true
%>
</li>
</ul>
</div>
<% end %>
</div>
<%= f.label :body, 'body' %>
<%= f.cktext_area :body, :ckeditor => {:width => "500"} %>
<%= f.label :tags, 'tags (comma separated)' %>
<%= text_field_tag :tags %>
<%= submit_tag 'submit' %>
<% end %>
</div>
This is the create action:
def create
#recipe = Recipe.new(params[:recipe])
photo_keys = params.keys.select{|k|k.match(/^photo/)}
#photos = []
photo_keys.each do |photo_key|
#photos << Photo.new(params[photo_key])
end
#recipe.tags = Tag.parse(params[:tags])
#recipe.author = current_user
if #recipe.save &&
#photos.all?{|photo|photo.save}
#photos.each do |photo|
photo.recipe_id = #recipe.id
photo.save
end
flash[:notice] = 'Recipe was successfully created.'
redirect_to recipe_url(#recipe.slug)
else
flash[:error] = 'Could not create recipe. '
flash[:error] += 'Please correct any mistakes below.'
render :action => :new
end
end
And this is the new action:
def new
#recipe = Recipe.new
end
I read that if I use form_for as I am using above, the fields will be re-populated automatically.
When I inspect #recipe.errors from within the erb template, I can see that the errors generated by create are also available when the new action is rendered, but the fields do not re-populate.
I'm actually not sure about what render action: does but what I do and works is: Instead of rendering the action just render the template using render :new.
You need to set the same instance variables (those with #), which you already in your create action.

Block in rails 3

My view:
<%= form_tag(rate_url) do %>
<%= hidden_field_tag :prod_id, params[:product_id] %>
<%= hidden_field_tag :rating_set_id, params[:rating_set_id] %>
<span class = "heading"> Recommendations </span>
<div><%= submit_tag 'Submit Ratings', :class => " btn right" %></div>
<span id = "rate_more_link">
<%= link_to "Rate More Products", products_path(:rating_set_id => params[:rating_set_id])%>
</span>
<br/>
<div id ="prods_container">
<% #recommendations.each do |rec| %>
<% url_raw = URI.parse("url_to_parse") %>
<% url = Net::HTTP.get_response(url_raw).body %>
<% if url.empty? %>
<% #title = "Product Unavailable via API" %>
<% #url = "#{rec.wmt_id}" %>
<% #cover_img = "_180X180.jpg" %>
<% #price = "Product Unavailable via API" %>
<% else %>
<% begin %>
<% #response1 = JSON.parse(url) %>
<% #title = #response1["ProductName"]%>
<% #url = "{#response1["ProductUrl"]}"%>
<% #cover_img = #response1["ImagePath"]%>
<% #price = #response1["currentItemPrice"]%>
<% rescue %>
<% end %>
<% end %>
<div id ="prod">
<span class = "radio_button">
<%= hidden_field_tag "recommendation_ratings[#{rec.id}][recommendation_id]", rec.id %>
<%= radio_button_tag "recommendation_ratings[#{rec.id}][rating]", '3'%> Good
<%= radio_button_tag "recommendation_ratings[#{rec.id}][rating]", '2'%> Fair
<%= radio_button_tag "recommendation_ratings[#{rec.id}][rating]", '1'%> Bad
<%= radio_button_tag "recommendation_ratings[#{rec.id}][rating]", '0'%> N/A
</span>
<div>
<a href='<%= #url %>' target="_blank">
<img src='<%= #cover_img %>' class='product_image_rec_table'></img>
</a>
</div>
<div class = "rec-desc">
<div class = "small"><b>Wmt ID: </b><%= rec.wmt_id %></div>
<div class = "small"><b>Title: </b><%= #title %></div>
<div class = "small"><b>Price: </b>$<%= #price %></div>
<div class = "em">
<b>Current Rating: </b>
<% rec.ratings.each do |rating_phin| %>
<%= rating_phin.label %>
<% end %></div>
<br/>
</div>
<div id="rec_note_text">
<%= text_field_tag "recommendation_ratings[#{rec.id}][notes]", "#{rec.notes}" ,:id => "rec_note_text", :placeholder => 'Enter Notes..'%>
</div>
</div>
<% end %>
<% end %>
</div>
I'm trying to move the <% end %> from the Current Rating block to the end so that I can call the rating_phin variable in my text_field_tag, however when I move the <% end %> to the end of my view, everything after the Current Rating block is not being rendered. What am I doing wrong? How can I update the rating_phin.notes instead of rec.notes in my text_field_tag at the end of my view?
That rating_phin variable only exists within the scope of that each loop.
If you require it later, you will have to loop again:
<div id="rec_note_text">
<% rec.ratings.each do |rating_phin| %>
<%= text_field_tag "recommendation_ratings[#{rec.id}][notes]", "#{rec.notes}" ,:id => "rec_note_text", :placeholder => 'Enter Notes..'%>
<% end %>
</div>
I'm not sure why you would expect that moving the <% end %> tag would be the right thing to do.
If you're getting lost inside of ERB, which is not especially difficult considering how fussy and convoluted HTML can get, especially when there's live Ruby in it, you might want to try HAML. It would reduce this down to about half the number of lines and remove a lot of the <% %> and closing tag debris that tends to make ERB hard to read.

How do I manage if-then explosion in view files?

I apologize if this doesn't follow good question guidelines, but I hope it's well in class with How to Manage CSS Explosion and receives a similarly helpful response.
I'm familiar with some basic view prolixity mitigation strategies such as the following:
Use helpers where appropriate
Don't repeat yourself
Use partials and layouts
Feel free to suggest something if I'm missing some big idea in the above list.
Nevertheless, I still end up with having several dimensions/degrees of freedom in my view, causing a lot of if-then statements or at least ternary blocks. For instance, in something I'm currently messing with, I'm working on a header bar for a program where the view is called when three "big" variables:
Whether the user is admin
Whether the user is logged in
Whether the page being viewed belongs to the user or someone else
It ends up looking like this mess:
<% content_for :subheader do %>
<div class="row">
<% if #user %>
<% if #user == current_user %>
<%= link_to 'My programs', user_programs_path(current_user), :class => 'active' %>
<% else %>
<%= link_to "#{#user.username}'s programs", user_programs_path(#user), :class => 'active' %>
<% end %>
<%= link_to 'Browse all programs', programs_path %>
<% else %>
<% if current_user %>
<%= link_to 'My programs', user_programs_path(current_user) %>
<% end %>
<%= link_to 'Browse all programs', programs_path, :class => 'active' %>
<% end %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>
Ugly. Readable and easily accessible, but ugly. Some suggestions?
Between experience and new technologies like LESS, I've become pretty good at slimming down my CSS files, but I'm still running into explosion issues with my MVC views.
I would use helpers and model definitions to dry up your code:
class User
def possesive
self == current_user ? 'My' : "#{username}'s"
end
end
module ...Helper
def user_program_link user
if user
link_to "#{user.possesive} programs", user_programs_path(user), :class => 'active'
elsif current_user
link_to 'My programs', user_programs_path(current_user)
end
end
end
You can then simplify all the if statements for the user_program_path calls to this:
<%= user_program_link #user %>
Which would reduce your view code to:
<% content_for :subheader do %>
<div class="row">
<%= user_program_link #user %>
<% if #user %>
<%= link_to 'Browse all programs', programs_path %>
<% else %>
<%= link_to 'Browse all programs', programs_path, :class => 'active' %>
<% end %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>
Continue this process to DRY up the rest of your code as well.
Rewrite the view code as follows:
<% content_for :subheader do %>
<div class="row">
<% if #user || current_user %>
<%= link_to ((current_user == #user or #user.nil?) ? "My programs" :
"#{#user.username}'s programs"),
user_programs_path(#user || current_user),
:class => 'active' %>
<% end %>
<%= link_to 'Browse all programs', programs_path,
:class => (#user ? '' : 'active') %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>

Resources