Error on data visualize on Ruby on Rails 4 - ruby

Sorry for my bad english, but I've this problem, for visualize some data from db I've make a Helper file, for manipulate and set the visualization and one Model for extract the rows from a DB and grouped all by date.
the problem is the Model return 0 (on :price) but the DB is full.
THIS IS THE HELPER:
module RoomsHelper
def rooms_chart_data(start = 3.weeks.ago)
rooms_by_day = Room.total_grouped_by_day(start)
(start.to_date..Date.today).map do |date|
{
reservation: date,
price: rooms_by_day[date].try(:total_price) || 0
}
end
end
end
THIS IS THE MODEL:
class Room < ActiveRecord::Base
def self.total_grouped_by_day(start)
rooms = where(reservation: start.beginning_of_day..Time.zone.now)
rooms = rooms.group("date(reservation)")
rooms = rooms.select("sum(price) as total_price, reservation")
rooms.group_by { |o| o.reservation.to_date }
end
end
AND I PASTE THE OUTPUT WRONG:
<div id="year_chart" data-rooms="[{"reservation":"2015-07-22","price":0},
{"reservation":"2015-07-23","price":0},{"reservation":"2015-07-24","price":0},{"reservation":"2015-07-25","price":0},{"reservation":"2015-07-26","price":0},{"reservation":"2015-07-27","price":0},{"reservation":"2015-07-28","price":0},{"reservation":"2015-07-29","price":0},{"reservation":"2015-07-30","price":0},{"reservation":"2015-07-31","price":0},{"reservation":"2015-08-01","price":0},{"reservation":"2015-08-02","price":0},{"reservation":"2015-08-03","price":0},{"reservation":"2015-08-04","price":0},{"reservation":"2015-08-05","price":0},{"reservation":"2015-08-06","price":0},{"reservation":"2015-08-07","price":0},{"reservation":"2015-08-08","price":0},{"reservation":"2015-08-09","price":0},{"reservation":"2015-08-10","price":0},{"reservation":"2015-08-11","price":0},{"reservation":"2015-08-12","price":0}]"
THIS IS THE DB TABLE:
class CreateRooms < ActiveRecord::Migration
def change
create_table :rooms do |t|
t.integer :identity_room
t.integer :price
t.integer :guest
t.datetime :reservation
t.timestamps null: false
end
end
end
AFTER ADD .to_s
module RoomsHelper
def rooms_chart_data(start = 3.weeks.ago)
rooms_by_day = Room.total_grouped_by_day(start)
(start.to_date..Date.today).map do |date|
{
reservation: date,
price: rooms_by_day[date.to_s].try(:total_price) || 0
}
end
end
end

You're converting the date to a string in the group(date(reservation)) and then trying to look up items in the hash with the string coerced date instead, e.g. rooms_by_day[date.to_s] rather than rooms_by_day[date]

Related

Obtaining total for associated columns

I have 4 models, User, ImageSize, Frame and CartItem. The CartItem model holds all the id's for the 3 prior models, so
class CartItem < ActiveRecord::Base
belongs_to :image_size
belongs_to :user
belongs_to :frame
end
create_table "cart_items", force: :cascade do |t|
t.integer "user_id"
t.integer "image_size_id"
t.integer "frame_id"
end
class User < ActiveRecord::Base
has_many :cart_items
end
My first issue here is this doesn't seem correct, as in my association setup, but for now ill address that another time.
A Frame and ImageSize both have a price column and what I am trying to achieve is to get the sum of the price for Frame and ImageSize for the current user so that Ii can show a subtotal for the user that collects the sum for all cartitems
How can I write this query or collect this data? Here is what I have managed to put together, but surely there's an easier way?
def show
#frame_total = CartItem.frame_price_total(current_or_guest_user)
#image_size_total = CartItem.image_size_price_total(current_or_guest_user)
#subtotal = CartItem.subtotal(#frame_total, #image_size_total)
end
class CartItem < ActiveRecord::Base
def self.frame_price_total(u)
#price_array = []
user = includes(:frame).where(user_id: u)
user.each do |f|
#price_array << f.frame.price
end
#price_array.sum
end
def self.image_size_price_total(u)
#price_array = []
user = includes(:image_size).where(user_id: u)
user.each do |f|
#price_array << f.image_size.price
end
#price_array.sum
end
def self.subtotal(image_size_total, frame_size_total)
total = image_size_total + frame_size_total
BigDecimal.new(total).to_s
end
end
It look good but have N+1 query problem
def show
#user_frames = CartItem.includes(:frame).where(user_id: current_user)
frame_array = []
#user_frames.each do |f|
frame_array << f.frame.price
end
#frame_total = frame_array.sum
end

Proper method for time completion in Ruby on Rails

I have a review section which allows a user to write a review of another user following their meetup. I want to permit users to write a review following the start_time of their meetup.
The problem I am having is, immediately upon a meetup between two users being created the users are allowed to write a review for one another before their meetup start_time. The method I created finished_meetup? is reading true all the time. I think this is due to my start_time being displayed wrong.
In the console, if I book a meetup for 8:30pm I get the following as the start_time start_time: "2000-01-01 20:30:00". Date is attached to time and cannot be eliminated because "Represent a time with no date in ruby".
How would I set up the method finished_meetup? to allow for the reviews to be done following the meetup and not beforehand.
shema.rb:
create_table "user_meetups", force: true do |t|
t.integer "user_id"
t.integer "friend_id"
t.string "state"
t.datetime "created_at"
t.datetime "updated_at"
t.date "start_date"
t.time "start_time"
user.rb
def find_corresponding_friend_id(friend_id)
self.user_meetups.where(friend_id:friend_id).present?
end
def already_reviewed
self.reviews.map{|d| d.review_writer_id}
end
def finished_meetup?
user_meetups.where("start_time < ?", Time.new("2000/#{Time.now.strftime("%m/%d")}"))
end
users/show.html.erb
<% if #user.find_corresponding_friend_id(current_user.id) && #user.already_reviewed.empty? && #user.finished_meetup? %>
user_meetup.rb
class UserMeetup < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
validates :start_date, :start_time, presence: true
# attr_accessor :user, :friend, :user_id, :friend_id, :state
after_destroy :delete_mutual_meetup!
state_machine :state, initial: :pending do
after_transition on: :accept, do: [:accept_mutual_meetup!]
after_transition on: :block, do: [:block_mutual_meetup!]
after_transition on: :unblock, do: [:accept_mutual_meetup!]
state :requested
state :blocked
event :accept do
transition any => :accepted
end
event :block do
transition any => :blocked
end
event :unblock do
transition any => :accepted
end
end
def self.request(start_date, start_time, location, description, learners, user1, user2)
transaction do
# Rails.logger.info "user1 is #{user1.inspect}"
# Rails.logger.info "user2 is #{user2.inspect}"
meetup1 = UserMeetup.create!(start_date: start_date, start_time: start_time, user: user1, friend: user2, state: 'pending')
# Rails.logger.info "meetup1 is #{meetup1.inspect}"
meetup2 = UserMeetup.create!(start_date: start_date, start_time: start_time, user: user2, friend: user1, state: 'requested' )
# meetup1.send_request_email
# meetup1
end
end
this method will return the list of user meetups started before the current time
def finished_meetup
self.user_meetups.where("start_time < ?", Time.now.to_s.gsub(/#{Date.today.to_s}/, '2000-01-01'))
end
Your date/time separation is complicating things. Change your start_time and start_date to a start_at datetime column. The migration will look something like this:
class SomeMigrationClass < ActiveRecord:Migration
def change
add_column :user_meetups, :start_at, :datetime
UserMeetups.find_in_batches.each do |um|
d = um.start_date
t = um.start_time
dt = DateTime.new(d.year, d.month, d.day, t.hour, t.min, t.sec, t.zone)
um.update!(start_at: dt)
end
remove_columns :user_meetups, :start_time, :start_date
end
end
This should preserve any existing data you have and combine them into datetimes. Untested of course, if you have production data test test test!
Next, just compare that datetime with the current date.
def finished_meetups
self.user_meetups.where('start_at < ?', Time.current)
end
This will return the user's meetups that have start_at times occurring before the current time.
If you really want a boolean response on whether there are any finished meetups, you could build on this with:
def finished_meetup?
self.finished_meetups.any?
end
What you have done is not a true or false case. It will either return an array or and empty array. Neither of which are ever false.
Try using "empty?"
def finished_meetup?
!self.finished_meetups.empty?
end
This is essentially asking if finished_meetups is NOT empty.

Rails -- ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column:

Having major Rails issues currently. I'm creating a School-Dashboard app that takes an xref table called Enrollments that relates Courses and Students.
Any time I try to update a grade for an Enrollment, I constantly get this line
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: UPDATE
"enrollments" SET "grade" = ?, "updated_at" = ? WHERE "enrollments"."" IS NULL
This line does not appear when I update attributes for Courses or Students. Only for the :grade attribute in Enrollment.
For some reason, it isn't being read properly, even though it is a legitimate attribute in my db for Enrollment (check out my schema).
I do all of my preliminary work in the rails sandbox.
Using ruby 2.1.1, Rails 4.1.0.rc1
I'd really love some help here.
Here are my corresponding models
class Student < ActiveRecord::Base
has_many :enrollments
has_many :courses, through: :enrollments
end
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, through: :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
end
The controllers:
Students
class StudentsController < ApplicationController
def index
#students = Student.all
end
def new
#student = Student.new
end
def show
end
def update
#student.update_attributes(student_params) ? redirect_to #student : render 'edit'
end
def create
#student = Student.new(student_params)
#student.save ? redirect_to #student : render 'new'
end
def destroy
end
def edit
end
private
def student_params
params.require(:student).permit(:first_name, :last_name, :student_number, :email)
end
end
Courses
class CoursesController < ApplicationController
def index
#courses = Course.all
end
def new
#course = Course.new
end
def show
end
def update
#course.update_attributes(course_params) ? redirect_to #course : render 'edit'
end
def create
#course = Course.new(course_params)
#course.save ? redirect_to #course : render 'new'
end
def destroy
end
def edit
# code here
end
private
def course_params
params.require(:course).permit(:course_name, :course_number)
end
end
Enrollments
class EnrollmentsController < ApplicationController
attr_accessor :course_id, :student_id, :grade
def index
#enrollments = Enrollment.all
end
def new
#enrollment = Enrollment.new
end
def create
#enrollment = Enrollment.new(enrollment_params)
#enrollment.save ? redirect_to #enrollment : render 'new'
end
def update
#enrollment.update_attributes(enrollment_params) ? redirect_to #enrollment : render 'edit'
end
def show
end
def destroy
#enrollment.destroy
end
def edit
# code here
end
private
def enrollment_params
params.require(:enrollment).permit(:course_id, :student_id, :grade)
end
end
And finally my schema.rb
ActiveRecord::Schema.define(version: 20140417152720) do
create_table "courses", force: true do |t|
t.string "course_name"
t.integer "course_number"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "enrollments", id: false, force: true do |t|
t.integer "course_id", null: false
t.integer "student_id", null: false
t.decimal "grade", precision: 5, scale: 2
t.datetime "created_at"
t.datetime "updated_at"
end
# noinspection RailsParamDefResolve
add_index "enrollments", ["course_id", "student_id"], name: "index_enrollments_on_course_id_and_student_id"
# noinspection RailsParamDefResolve
add_index "enrollments", ["student_id", "course_id"], name: "index_enrollments_on_student_id_and_course_id"
create_table "students", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.integer "student_number"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Looks like I figured it out on my own!
So here's a bit of rails convention that needs to be addressed. The problem was with my database setup for 'Enrollments'. When I run the command
rails g migration CreateJoinTableEnrollments course student
Rails does too much work for me in my migration file (except for the table name and grade, I added that)
class CreateJoinTableEnrollments < ActiveRecord::Migration
def change
create_join_table :courses, :students, table_name: :enrollments, id: false, force: true do |t|
t.index [:course_id, :student_id], null: false
t.index [:student_id, :course_id], null :false
t.decimal :grade, precision: 5, scale: 2
t.timestamps
end
end
end
In reality, I didn't need any of that. In order to manipulate specific data in a row for Enrollments, there has to be an identifier for that row. With id: false, force: true that option got nullified. I also simplified things with the indexing. I just created regular old columns instead. Now my migration file looks like this.
class CreateJoinTableEnrollments < ActiveRecord::Migration
def change
create_table :enrollments do |t|
t.integer :course_id, null: false
t.integer :student_id, null: false
t.decimal :grade, precision: 5, scale: 2
t.timestamps
end
end
end
And with that, no issues! I've just been breaking my head over that for the past 2 days. Hope this helps anyone else who has this issue.

Trouble getting the timestamp attributes for Active Record

So I'm trying to get the updated at attribute for my database object, but it's not working. I can get the other attributes but not the updated_at or created_at attributes. I'm also noticing that I can't get the id attribute as well. It seems as if anything I haven't declared in my Pocket.new does not exist. Here's my code:
By the way, I'm not using rails. I'm using sinatra-activerecord and sinatra.
Model
class Pocket < ActiveRecord::Base
def retrieve(consumer_key)
url = "get/"
pocket_url = join_url(url)
# time = Time.now.to_i
token = self.token
puts consumer_key
puts self
puts time = self.updated_at #.to_i this is where it happens.
options = {
:access_token => token,
:consumer_key => consumer_key,
:since => (time if defined? time)
}
hello = RestClient.post pocket_url, options
# JSON.parse(hello)
end
Controller
get '/auth/pocket/callback' do
[…]
pocket = Pocket.new(token: #token, user: #user)
DB migration
class CreatePocket < ActiveRecord::Migration
def up
create_table :pockets do |t|
t.string :user
t.string :token
t.timestamps
end
end
def down
drop_table :users
end
end
id, created_at, and updated_at are going to be nil for un-persisted objects, which is what you have by just calling .new and not saving the object yet.
Those attributes will be sent as soon as you call .save (assuming there are no validation errors).
Actually that isn't 100% true. updated_at will not be set on the first create / save, but it will be set on subsequent saves.

ActiveRecord::Migration - Referencing a table in another schema

I'm using Ruby and PostgreSQL and have created 3 distinct DB schemas: billing (for billing related data), customer (for customer related data) and edocs (for electronic documents related data).
I'm not using Rails so I have a stand-alone migration code like this:
#migrate.rb
if ARGV[0] =~ /VERSION=\d+/
version = ARGV[0].split('=')[1].to_i
else
version = nil
end
ActiveRecord::Base.default_timezone = :utc
#logger = Logger.new $stderr
ActiveRecord::Base.logger = #logger
ActiveSupport::LogSubscriber.colorize_logging = false
#config = YAML.load_file(File.join(File.dirname(__FILE__), 'database.yml'))
ActiveRecord::Base.establish_connection(#config["edocs"])
ActiveRecord::Migrator.migrate(".", version)
I have already realized that I probably have to create a different directories to contain the migration for the different schemas, and changing connection info for each migrate.rb.
But I'm not sure how I'm going to make a table reference another table that is in another schema.
For example:
class CreateBillingEventsTable < ActiveRecord::Migration
def self.up
create_table :billing_events do |t|
t.references :customer, :null => false
t.references :service_type, :null => false
t.timestamps
end
change_table :billing_events do |t|
t.index [:customer_id, :created_at]
end
end
def self.down
remove_index :billing_events, :column => [:customer_id, :created_at]
drop_table :billing_events
end
end
In the above example, "customer" and "billing_events" are in different schemas.
How can I code that?
Thanks.

Resources