I'm creating a small lesson app, with a different lesson for each day. I'm wanting to show the current days lesson only on the index, and can't figure out how. I googled and found some info that came close, but still couldn't fix the problem. I only have one controller, DaysController. No user controller.
For my model(day.rb) I've tried this
class Day < ActiveRecord::Base
validates :description, :date, :link_to, :presence => true
scope :created_on, lambda {|date| {:conditions => ['created_at >= ? AND created_at <= ?', date.beginning_of_day, date.end_of_day]}}
def self.today
self.created_on(Date.today)
end
end
And for my index I've tried these
<% #day.created_on(Date.today) %>
<% #day.today %>
any advice??
If I understand correctly and for simplicity sake is this essentially what you are trying to achieve?
Controller:
def index
#days = Day.all
end
View (index.html.erb):
<% #days.each do |day| %>
<% if day.created_at == Date.today %>
<%= day.field_name %>
<% end %>
I would change the scope to just use the Date object and I assume that you want your condition to use the newer syntax:
scope :created_on, ->(date) { where(created_at: date) }
Then the Day.today method should work without any change.
You can do the following:
class Day < ActiveRecord::Base
scope :today, lambda { where('CAST(created_at AS date) = ?', Date.today) }
And use it like this:
#days = Day.today
# returns a list of `Day` records where the `created_at`'s date is equal to today's date
Related
I am building a basic student planner application using Ruby on Rails and I am trying to implement a way for a student to see which assignments are due within the next seven days. I would like to use a scope method, something like due_soon that can be called within a view.
Currently when I run my code I'm getting an ArgumentError in Assignments#index and it's telling me that the comparison of Date with :due_date failed
My Assignments model:
class Assignment < ActiveRecord::Base
belongs_to :course
belongs_to :student
# accepts_nested_attributes_for :course
validates :course_id, :student_id, :due_date, :title, presence: true
scope :due_soon, -> { where(Date.current + 7.days >= :due_date) }
def course_attributes=(attributes)
binding.pry
if attributes[:course_name].blank?
self.course = Course.find_by(id: params[:course_id])
else
self.course = Course.find_or_create_by(attributes)
self.course
end
end
end
In my view:
<h3>Due Soon</h3>
<% Assignment.due_soon.each do |assignment| %>
<% if assignment.course %>
<tr>
<td><%= assignment.title %></td>
<td><%= assignment.course.course_name %></td>
<td><%= assignment.due_date %></td>
<td><%= link_to "View/Edit Assignment", student_assignment_path(#student, assignment) %></td>
</tr>
<% end %>
<% end %>
Any pointers would be much appreciated as I try and continue to familiarize myself with rails! Thanks!
The issue you are having here is related to your usage of where:
Assignment.where(Date.current + 7.days >= :due_date)
Is not valid for ActiveRecord's where method.
What you need is to either use ActiveRecord's lib to generate SQL (1), or write the SQL yourself (2):
# (1) Use ActiveRecord combined with a Ruby Range
Assignment.where(due_date: Date.current..7.days.from_now)
# (2) Assignment.where('due_date between ? and ?', Date.current, 7.days.from_now)
You have a syntax error there.
One way is...
scope :due_soon, -> { where('due_date =< ?', Date.current + 7.days) }
https://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/scope
I am trying to check the day and hours of a business to determine if its open or not.
I have this code in my supplier partial
%li
= link_to shopping_supplier_path(supplier) do
= content_tag :div, class: 'grid-block' do
= content_tag :div, supplier.image_available, :class => 'small-3 grid-content'
= content_tag :div, :class => 'small-9 grid-content' do
%h4= supplier.name.truncate(30).titlecase
= content_tag :div, class: 'grid-block' do
.small-3.grid-content 9/10
.small-3.grid-content $$
.small-6.grid-content.text-right
- SupplierTradingHour.open.includes(:supplier).each do |hour|
= "#{hour.supplier.name} is open! It closes at #{hour.close_time}."
TradingHour Model
class SupplierTradingHour < ActiveRecord::Base
belongs_to :supplier
scope :open, lambda { |day, time| { :conditions => ["self.weekday = ? AND self.open_time >= ? AND self.close_time < ?", day, time, time] } }
end
As an alternative implementation, you might want to consider using the following gem for business hour related functionalities:
https://github.com/Intrepidd/working_hours
You are calling the open scope without arguments: SupplierTradingHour.open but your :open scope is a lambda expression with two arguments |day, time| which one of the reasons why your code is failing.
Your SQL logical expression is also not correct: open_time <= ? AND close_time > ? (note the operators are the opposite of yours)
In your case, for a DIY implementation (without using third party gems) I would suggest doing this:
#app/models/trading_hour.rb
class TradingHour < ActiveRecord::Base
belongs_to :supplier
scope :open_now, -> (day, time) { where("weekday = ? AND open_time <= ? AND close_time > ?", day, time, time) }
end
then in your supplier model:
#app/models/supplier.rb
class Supplier < ActiveRecord::Base
has_many :trading_hours
def opening_status day, hour
today_trading_hours = trading_hours.open_now(day, hour)
if today_trading_hours.size > 0
"Opened until #{today_trading_hours.first.close_time}H"
else
"Closed"
end
end
end
Then from your view call
#if today is day 1
#and current hour is 12
supplier.opening_status(1, 12)
setting a scope is fine but I would probably just define my #suppliers with something like:
#suppliers = Supplier.where("weekday = ? AND open_time > ? AND closing_time < ?", day, time, time)
Another option, if you need both sides of it in different circumstances, would be to write an instance method is_open?
I have a record called Feeds that contains the field 'last_visited' and 'last_modified', both are timestamps.
I'm trying to render a list in a view of alls Feeds where last_modified > last_visited.
I currently have this:
Controller
#feeds = #user.feeds
#feeds_hot = #feeds.where(['#feeds.last_modified > ?', #feeds.last_visited])
Have a feeling I'm way off track here. Should I also being using a model class to do this?
Any helps is greatly appreciated.
Edit:
Here's my model
class Feed < ActiveRecord::Base
attr_accessible :feed_id, :feed_url, :last_modified, :title, :url, :last_visited, :user_id
belongs_to :user
scope :hottest, lambda {where('last_modified > ?', :last_visited)}
def fetch_feed!
feed = Feedzirra::Feed.fetch_and_parse(feed_url) # probably want some eror handling here
self.title = feed.title
self.url = feed.url
self.last_modified = feed.last_modified
self.last_visited = feed.last_modified
self #or nil if you like
end
def self.check_for_update(feed)
fetched_feed = Feedzirra::Feed.fetch_and_parse(feed.feed_url)
entry = fetched_feed.entries.first
feed.last_modified = entry.published
end
def update_visit_date!
date = Time.now
update_attribute(:last_visited, date)
self
end
end
Edit
Updated code
Controller
def home
#user = current_user
#feeds = #user.feeds
#feeds_hot = #feeds.hottest
end
Model
attr_accessible :feed_id, :feed_url, :last_modified, :title, :url, :last_visited, :user_id
belongs_to :user
scope :hottest, lambda {where("'last_modified' > ?", 'last_visited')}
View
%ol.feeds.feeds_hot
- #feeds_hot.each do |feed|
%li.feed.hot[feed]
= render :partial => 'feeds/feed_link', :locals => {:feed => feed}
Unfortunately it's still not rendering the hot feeds in the view when I have a feed with the following data:
Last Modified 2013-06-14 23:49:07 UTC
Last Visited 2013-06-14 23:47:55 UTC
Last Modified is a few hours > than Last Visited
If you're looking to get a list of all feeds that have been modified more recently than the most recent visit on any feed, the following will work:
last_visit = Feed.order("last_visited").last.last_visited
#feeds = #user.feeds
#hot_feeds = Feed.where("last_modified > ?", last_visited)
EDIT:
Based on your comments and a re-reading of your question, the code posted above will not accomplish what you're trying to do. Since you're trying to get a list of all invites where each has been modified since it was last visited, you'll want to create a model scope to do the lookup with ActiveRecord. The following code should work:
# app/models/feed.rb
class Feed < ActiveRecord::Base
scope :hottest, lambda {where('last_modified > ?', :last_visited)}
end
Then, you can run the following in a console, controller, or view:
#user.invites.hottest
#=> array of all the user's invites that have been modified more recently than they have been viewed
I'm working on a little time tracking application and ran into a problem I don't know how to solve. I have a Task model and a Client model. Each task belongs to a client.
class Task < ActiveRecord::Base
belongs_to :client
attr_accessible :client_id, :description, :start, :end
scope :yesterday, -> {
where('start > ?', Date.yesterday.to_time).where('start < ?', Date.today.to_time)
}
end
class Client < ActiveRecord::Base
attr_accessible :name
has_many :tasks
end
Right now I'm displaying a list of tasks scoped by the day the tasks were completed, and ordered by the time they were completed. I would like to display that same list, but grouped by the client, and sorted by the client name. Here's what I would like to do:
<div id="yesterday_summary">
<% #yesterday_clients.each do |client| %>
<h2><%= client.name %></h2>
<ul>
<% client.tasks.each do |task| %>
<li><%= task.description %></li>
<% end %>
</ul>
<% end %>
</div>
In my controller I currently have:
#tasks_yesterday = Task.yesterday
#yesterday_clients = group_tasks_by_client #tasks_yesterday
And in the group_tasks_by_client method, I have some pretty ugly code that isn't even working at the moment:
def group_tasks_by_client(tasks)
clients = []
tasks.collect(&:client).each do |client|
clients << {client.id => client} unless clients.has_key? client.id
end
clients_with_tasks = []
clients.each do |client|
c = Struct.new(:name, :tasks)
cl = c.new(client.name, [])
tasks.each do |task|
cl.tasks << task if task.client_id = client.id
end
clients_with_tasks << cl
end
clients_with_tasks
end
I'm sure there is a clean, simple, rails-way to do this but I'm not sure how. How can this be done?
You can have the database do this for you like so:
#yesterdays_clients = Client.includes(:tasks).merge(Task.yesterday).order(:name)
Besides being cleaner, it's more efficient since it gets all your clients and tasks in one pass. The original code was subject to N+1 queries because there was no eager loading.
BTW, you can make your scope simpler as well:
scope :yesterday, -> { where(:start => (Date.yesterday.to_time...Date.today.to_time)) }
I am using this named_scope to search for products that have a description matching any word the user inputs.
E.g., Product.description_like_any("choc pret")
Will return products with names like
"Chocolate Bar"
"Chocolate Covered Pretzels"
"Miniature Chocolate Ponies"
Here's the named_scope I've written (which works)
named_scope :description_like_any, (lambda do |query|
return {} unless query
conditions = []
values = []
for q in query.split(/\s+/)
conditions << "(`products`.description LIKE ?)"
values << "%#{q}%"
end
{ :conditions => [conditions.join(' AND '), *values] }
end)
Is there a better way to write this? Perhaps I'm missing a Rubyism/Railism or two?
Solution
Using scope_procedure in conjunction with Searchlogic, this can be done in an even easier way. Note, the solution before even leverages Searchlogic's _or_ syntax for connecting two scopes together. The :keywords scope_procedure finds products matching product.description, or product.vendor.name; All with one text field!
Model
# app/models/product.rb
class Product < ActiveRecord::Base
scope_procedure :keywords, lambda |query|
description_like_any_or_vendor_name_like_any(query.split(/\s+/))
end
end
Controller
# app/controllers/products_controller.rb
class ProductsController < ApplicationController
def index
#search = Product.search(params[:search])
#products = #search.all
end
end
Views
# app/views/products/index.html.erb
<% form_for #search do |f| %>
<%= f.label :keywords, "Quick Search" %>
<%= f.input :keywords %>
<%= f.submit, "Go" %>
<% end %>
The most Railsy thing to do is to not write this yourself. :-) Use the excellent Searchlogic gem which will create the description_like_any scope for you.
Edit: If you want your user to be able to enter search terms in a free text field like this, you can define your own scope:
class Product < ActiveRecord::Base
# ...
scope_procedure :description_like_any_term, lambda { |terms|
name_like_any(terms.split(/\s+/))
}
# ...
end