method of an object in index controller - ruby-on-rails

This is a really simple question, but for some reason I cannot find the solution.
My controller is:
def index
#events = Event.all
#I want something here for a single event
distance = Time.now.to_date.distance_to(#event.event_date)
#days = distance[:days]
#months = distance[:months]
#years = distance[:years]
end
Then in the view:
<table>
<tbody>
<% #events.each do |event| %>
<tr>
<td><%= event.title %></td>
<td><%= event.event_date %></td>
<td> Just <%= #days %> days, <%= #months %> months and <%= #years %> years for the event </td>
</tr>
<% end %>
</tbody>
</table>
Of course it doesn't work because there is no #event.
How can I do it?
Thanks in advance!

What you are looking to do is add that functionality to individual records
I would add distance as a method on the Event class
so
class Event < ActiveRecord::Base
#... your model code here
def distance
Time.now.to_date.distance_to(self.event_date)
end
end
the controller
def index
#events = Event.all
end
and in the view
<td> Just <%= event.distance[:days] %> days, <%= event.distance[:months] %> months and <%= event.distance[:years] %> years for the event </td>
You could add some more methods to your model to make it prettier like event.distance_days or something but I will leave that as an exercise for the reader.

"I want something here for a single event."
The default way to find single records is by id:
#event = Event.find(params[:id])
But to me, it should work like that because I don't see #event called in the view.

Related

Rails /(year)/(month)/(day) separate pages

I'm very new to rails and am having some trouble. I have a model called BusinessDates that consists of two tables, calendar_date and seasonality (you can ignore seasonality). What I'm trying to achieve is to be able to move through them easily like folders.
It took me a few solid days of google-foo, but I was able to have the index display a list of each unique year in order as links with friendly_ids. From here I want to click on it and have it link to a new view that displays a list of each unique month in that particular year in order as links with friendly_ids. Then (as you could guess) have it display on another new view a list of all the days in the selected month in the selected year. I want the url to be business_dates/2016/5/21 or in other words business_dates/(year)/(month)/(day).
My issue: I don't know where to go from here. I can't even seem to find any info on making a second level deep non-static url without either making each year month and day separate models (want to avoid that), or what looks like a rube goldberg machine to kinda get there but without views for each page (You'd have to just type the full date into the url).
Please help a beginner who feels very lost!
Controller:
def index
#years = BusinessDate.pluck(:calendar_date).map{|x| x.year}.uniq
end
index.erb.html
<table>
<tr>
<th>Year</th>
</tr>
<% #years.sort.each do |year| %>
<tr>
<td><%= link_to year, business_date_path(year) %></td>
</tr>
<% end %>
</table>
You can create a custom route. Since I don't know the exact controller actions etc that you are using, I will give you a general answer. You can route like (will hit BusinessDatesController's :show_full_date action):
get 'business_dates/:year/:month/:day', to: 'business_dates#show_full_date'
You can link to it like (run rake routes to check correct path):
<%= link_to your_date, full_date_business_dates_path('1985','5','21') %>
The important thing to understand here is that the path helper is in the end just a method that can take arguments. What it can accept is defined in the routes.rb. So, in our case, it will :year, :month and :day parameters.
Once you click this link and hit the :show_full_date action, you can extract the year, month, date using params[:year], params[:month], params[:day] and do with them whatever you need to do. You can similarly define routes for just the year or the month. Hope this helps.
EDIT: You can also give the as: option in the route definition to give a specific name to the path, like as: 'my_funky_name'.
Also, I should add that you should keep such custom routes to a minimum. When it is necessary, then do it. Otherwise stick to the defaults.
I finally figured it out and got it working, so I'll share my answer. big props to arunt for the help! It's a bit messy and probably not the right way I should be doing this, but my first goal was to get it to work and learn how it works along the way. Now I'm looking to tidy up and learn best practices.
Routes
Rails.application.routes.draw do
resources :business_dates, except: :show
get '/business_dates/:year/:month/:day', to: 'business_dates#edit_date', as: 'edit_date'
get '/business_dates/:year/:month', to: 'business_dates#by_days', as: 'by_days'
get '/business_dates/:year', to: 'business_dates#by_months', as: 'by_months'
delete '/business_dates/:year/:month/:day', to: 'business_dates#delete_date', as: 'delete_date'
Controller
class BusinessDatesController < ApplicationController
def index
#business_dates = BusinessDate.all
#years = BusinessDate.pluck(:calendar_date).map{|x| x.year}.uniq
end
def new
#date = BusinessDate.new
end
def by_months
#months = BusinessDate.where("strftime('%Y', calendar_date) = ?", params[:year])
#months = #months.pluck(:calendar_date).map{|x| x.strftime('%m')}.uniq
end
def by_days
#days = BusinessDate.where("cast(strftime('%Y', calendar_date) as int) = ? AND cast(strftime('%m', calendar_date) as int) = ?", params[:year], params[:month])
end
def edit_date
set_business_date
end
def create
#date = BusinessDate.new(date_params)
if #date.valid?
#date.save
redirect_to by_days_path(#date.calendar_date.year, "%02d" % #date.calendar_date.month)
else
flash.now[:alert] = "New business date could not be saved"
render action: "new"
end
end
def update
#set_business_date
#date = BusinessDate.find(params[:id])
#date.update(date_params)
redirect_to by_days_path(#date.calendar_date.year, "%02d" % #date.calendar_date.month)
end
def delete_date
set_business_date
#date.destroy
redirect_to by_days_path(params[:year], params[:month])
end
private
def set_business_date
#date = BusinessDate.where("cast(strftime('%Y', calendar_date) as int) = ? AND cast(strftime('%m', calendar_date) as int) = ? AND cast(strftime('%d', calendar_date) as int) = ?", params[:year], params[:month], params[:day]).first
end
def date_params
params.require(:business_date).permit(:calendar_date, :seasonality)
end
end
index.html.erb
<h1>Business Dates by Year</h1>
<table>
<tr>
<th>Calendar Date</th>
</tr>
<% #years.sort.each do |year| %>
<tr>
<td><%= link_to year, business_date_path(year) %></td>
</tr>
<% end %>
</table>
<br>
<%= link_to 'Create New Business Date', new_business_date_path %>
by_months.html.erb
<h1><%= params[:year] %></h1>
<table>
<tr>
<th>Months</th>
</tr>
<% #months.sort.each do |month| %>
<tr>
<td><%= link_to Date::MONTHNAMES[month.to_i], by_days_path(params[:year], month) %></td>
</tr>
<% end %>
</table>
<br>
<%= link_to 'Create New Business Date', new_business_date_path %>
<br>
<%= link_to 'Back to Years', business_dates_path %>
by_days.html.erb
<h1><%= Date::MONTHNAMES[params[:month].to_i] %>, <%= params[:year] %> <%= params[:id] %></h1>
<table>
<tr>
<th>Date</th>
<th>Seasonality</th>
<th>ID</th>
</tr>
<% #days.sort.each do |day| %>
<tr>
<td><%= day.calendar_date.day %></td>
<td><%= day.seasonality %></td>
<% %>
<td><%= day.id %></td>
<td><%= link_to 'Edit', edit_date_path(day.calendar_date.year, "%02d" % day.calendar_date.month, day.calendar_date.day) %></td>
<td><%= link_to 'Delete', delete_date_path(day.calendar_date.year, "%02d" % day.calendar_date.month, day.calendar_date.day), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br>
<%= link_to 'Create New Business Date', new_business_date_path %>
<br>
<%= link_to 'Back to Months', by_months_path %>
<br>
<%= link_to 'Back to Years', business_dates_path %>
It's all working fine, but I wish I could figure out my :id issue. Not sure how to find a record by :id while using the :year/:month/:day url convention. It's not an issue for this app, considering there should never be more than one of the same date, but it'd be helpful and I'm sure it would cut down on having to search for the record by params[:year],[:month], and [:day]. This thing was a holy terror, but I certainly learned a lot about the differences between arrays, hashes, symbols, attributes, models, methods, and instance variables along the way!

Ruby on rails-Tabular form for input taken from user

I want to print in tabular form the entries given by user. The table will contain 3 columns for name,registration number and classes attended, however the output is not as expected. Its first printing all the names and then all the registration numbers and so on. I want to print a name and the registration number according to name and classes attended.
</head><table width="100%">
<tr>
<th>NAME</th>
<th>REGISTRATION NUMBER</th>
<th>CLASSES ATTENDED</th>
</tr>
<tr>
<% #name_students.each do |t| %>
<th><%= t.name_student %></th><br>
<% end %>
<% #reg_nos.each do |t| %>
<th><%= t.reg_no %></th><br>
<% end %>
<% #classes_ats.each do |t| %>
<th><%= t.classes_at %></th><br>
<% end %>
</tr>
</table>
Here is my controller action.
class PagesController < ApplicationController
def home
#name_students = Page.all
#reg_nos = Page.all
#classes_ats = Page.all
end
def list
#name_students = Page.all
#reg_nos = Page.all
#classes_ats = Page.all
end
def add
Page.create(:name_student => params[:nam])
Page.create(:reg_no => params[:reg])
Page.create(:classes_at => params[:cls])
redirect_to :action => 'home'
end
end
If I understand what you're doing, you should probably have PagesController#home return something like #pages = Page.all object and display the data kind of like this:
<thead>
<tr>
<th>Name</th>
<th>Registration Number</th>
<th>Classes Attended</th>
</tr>
</thead>
<tbody>
<% #pages.each do |p| %>
<tr>
<td><%= p.name %></td>
<td><%= p.registration_number %></td>
<td><%= classes_attended(p.classes_attended) %></td>
</tr>
<% end %>
</tbody>
Above, classes_attended(p) is a call to a helper method that you would use to map the class names of the classes that student attended into an display-able array. Really, that kind of display logic might be better in a decorator, but a helper method should be fine for now.
Let me know if I've totally misunderstood what you're doing, and I'll delete my answer.
Edit to add:
Example index method:
def home
#pages = Page.all
end
Also, looking at your question again, is there a reason you're creating three Page objects with one attribute each instead of one Page object with all three attributes? It should probably look something like Page.create(:name_student => params[:nam], :reg_no => params[:reg], :classes_at => params[:cls]). That's pretty much the only way the solution I posted will work. Again, though, I might be totally misunderstanding what you're going for.

rails will_paginate not work with search results

I'm following the advanced search form revised from railscasts and i'd like to paginate search results but I don't know where put the code for pagination.
I have a model:
mineralisearch.rb
class Mineralisearch < ActiveRecord::Base
attr_accessible :keywords,:keywords1
def segnalazione_mineralis
#segnalazione_mineralis ||= find_segnalazione_mineralis
end
private
def find_segnalazione_mineralis
segnalazione_mineralis = SegnalazioneMinerali.order(:titolo)
segnalazione_mineralis = segnalazione_mineralis.where("titolo like ?", "%#
{keywords}%") if keywords.present?
segnalazione_mineralis
end
end
I have a controller
mineralisearches_controller.rb
class MineralisearchesController < ApplicationController
def new
#mineralisearch = Mineralisearch.new
end
def create
#mineralisearch = Mineralisearch.create!(params[:mineralisearch])
redirect_to #mineralisearch
end
def show
#mineralisearch = Mineralisearch.find(params[:id])
end
end
and a view
show.html.erb
<h1>Risultati della ricerca</h1>
<table class="table1">
<tr>
<th>Titolo:</th><br>
<th>Creato il:</th>
<th>Ultima Modifica il:</th>
<th></th>
</tr>
<%= render #mineralisearch.segnalazione_mineralis %>
</table>
with this partial
_segnalazione_minerali.html.erb
<tr>
<td><%= segnalazione_minerali.titolo %> </td>
<td><%= l(segnalazione_minerali.created_at, format:"%e %B %Y %k:%M:%S") %></td>
<td><%= l(segnalazione_minerali.updated_at, format:"%e %B %Y %k:%M:%S")%></td>
<td><%= link_to 'Mostra', [segnalazione_minerali.user, segnalazione_minerali]%></td>
</tr>
I know that I must put some code like
#mineralisearch = Mineralisearch.order("Titolo").page(params[:page]).per_page(10)
in the controller
and
<%= will_paginate #mineralisearch, :previous_label => 'Prec', :next_label => 'Succ' %>
but I really don't know where! I tried to put these in the show view and in the controller but they don't work!
Thanks all for help
According to will_paginate
This code
#mineralisearch = Mineralisearch.order("Titolo").page(params[:page]).per_page(10)
should be like this
#mineralisearch = Mineralisearch.order("Titolo").paginate(:page => params[:page],:per_page => 10)
And you can have this
<%= will_paginate #mineralisearch, :previous_label => 'Prec', :next_label => 'Succ' %>
in your show view.
But it is not a normal thing to have pagination in the show view currently which you wants.It is much preferred to have pagination on the index view.If you want to have like this,then you have to move the respected controller code snippet to index action and the view code snippet to the index.html.erb file.

Rails getting the error: First argument in form cannot contain nil or be empty

I've been getting this error for a couple days and I'm totally blocked. I tried redoing the model (I'm following the rails starting guide) and just not getting anywhere.
First argument in form cannot contain nil or be empty
I have time_delta as a nested class of stock im trying to create a form to view and create new time_deltas on a stock's show and I keep getting the above error.
Heres my time_delta controller:
class TimeDeltasController < ApplicationController
def new
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build
respond_with(#time_delta)
end
def create
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build(params[:stock])
#time_delta.save
end
end
Heres my view for the specific stock
<h1> Stock </h1>
<table>
<tr>
<th>Stock</th>
<th>Hashtag</th>
</tr>
<tr>
<td><%= #stock.name %></td>
<td><%= #stock.hashtag %></td>
</tr>
</table>
<h2>Deltas: </h2>
<table>
<tr>
<th>Stock</th>
<th>Hashtag</th>
</tr>
<% #stock.deltas.each do |delta| %>
<tr>
<td><%= #delta.start %></td>
<td><%= #delta.length %></td>
</tr>
<% end %>
</table>
<h2>Add a TimeDelta:</h2>
<%= form_for([#stock,#time_delta]) do |f| %>
<p>
<%= f.label :start %><br>
<%= f.text_field :start %>
</p>
<p>
<%= f.label :length %><br>
<%= f.text_area :length %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', stocks_path%>
<%= link_to 'Edit', edit_stock_path(#stock)%>
Heres how I added the route in my routes.rb:
resources :stocks do
resources :time_deltas
end
Any information would be greatly appreciated, I'm really stuck.
EDIT: Stocks controller stuff
def show
#time_delta = #stock.time_deltas.build
#stock = find_stock
end
private
def find_stock
return Stock.find(params[:id])
end
You are trying to access #time_delta variable in your stocks/show view, but it is not set. Add the following line to StocksController#show action.
#time_delta = #stock.time_deltas.build
EDIT:
Also there is a problem with the naming of your TimeDelta model, because in Ruby 'delta' is plural of 'deltum'. To adhere to Rails conventions, change the the model name to TimeDeltum or alternatively tell Rails to use 'deltas' as the plural form of 'delta'. You can learn how to do it here.
The error basically means you've not set the variables for use in form_for
As you're a beginner, let me explain how it works:
form_for is basically an instance method (helper) which takes ActiveRecord objects, and outputs them into an HTML form. Your definitions of elements (f.____field) are for the method to determine which HTML to output
Like all methods, form_for has arguments/parameters which it relies on to help the method run correctly. The parameters for form_for include a correctly formatted ActiveRecord object, which is why you have to call Model.new each time you want to use it
Your error means the method cannot process the variables (objects) you've sent, either from lack of data (empty) or non-existence (nil). To fix this, as #vee has mentioned, you need to make sure your form_for is receiving the correct data
I would try this:
class TimeDeltasController < ApplicationController
def new
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build
respond_with(#stock, #time_delta)
end
def create
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build(params[:stock])
#time_delta.save
end
end
You should read up on respond_with to see how it works

Ruby on Rails - How to combine display Search results in the View

I have Search controller that searches 2 models - Posts and Categories. The search works, however I am unable to display results in the View correctly - I can't get category names to show up.
I am very confused and frustrated at this point and hope to find some help!
I'm pretty sure (99% sure) the problem is in the View somewhere, because I can get results to display through render inspect thingy.
SearchController.rb
class SearchController < ApplicationController
def index
#posts = Post.search(params[:search])
#categories = Category.search(params[:search])
# combine the results
#results = #posts + #categories
#results.uniq # may be necessary to remove duplicates
end
end
index.html.erb (views/search)
<%= render 'posts/posts', :posts => #posts %>
_posts.html.erb (view/posts)
<h1>Listing posts</h1>
<table>
<tr>
<th>Name</th>
<th>Category</th>
<th>Description</th>
<th>Flag</th>
</tr>
<% if posts %>
<% posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.category.name %></td>
<td><%= post.description %></td>
<td><%= post.flag %></td>
</tr>
<% end %>
<% else %>
<tr><td>No posts</td></tr>
<% end %>
</table>
I can get posts that match the search to display, but I can't display categories. How can I do this? Any help highly appreciated!! Thank you.
If you are using a search backend like sunspot solr then you would be able to combine the searches like
#search = Sunspot.search [User, Company] do
fulltext params[:search]
end
#results = #search.results
And then return the necessary values. In this example, it's showing where you can retrieve the class of the action (controller_name) may not work depending on which controller the results are returned in.
<% #results.each do |result| %>
<% case result.class.to_s %>
<% when "Company" %>
<li><%= "Company: #{result.name}" %></li>
<% when "User" %>
<li><%= "User: #{result.username}" %></li>
<% end %>
<% end %>
The answer (I include all the things I changed to make it work + few files that I didn't change but that have to be there), or How to make simple search for multiple models:
SearchController.rb
class SearchController < ApplicationController
def index
#posts = Post.search(params[:search])
end
end
post.rb
class Post < ActiveRecord::Base
attr_accessible :category_id :name :description :flag
belongs_to :category
def self.search(search)
if search
find(:all, :joins => :category, :conditions => ['posts.equipment LIKE ? OR posts.description LIKE ? or categories.name like ?', "%#{search}%", "%#{search}%", "%#{search}%"])
else
find(:all)
end
end
search/index.html.erb
<%= render 'posts/posts', :posts => #posts %>
I added 2 files _post.html.erb and _category.html.erb. They are similar, this is _post.html.erb:
post: <%= post.name %>
(This might not be necessary in some cases or for some models. I can search a third model without this file in its' views. However the third model doesn't have file like _posts.html.erb either).
Finally, _posts.html.erb remains the same:
...
<% if posts %>
<% posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.category.name %></td>
<td><%= post.description %></td>
<td><%= post.flag %></td>
</tr>
<% end %>
<% else %>
<tr><td>No posts</td></tr>
<% end %>
...
This works now. Can add new models to the search easily. The only other thing needed for the search is input field.

Resources