Proper method for time completion in Ruby on Rails - ruby

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.

Related

Error on data visualize on Ruby on Rails 4

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]

rom-rb form validation when using multiple relations

I'm trying out http://rom-rb.org/ and can't figure out how to get a presence validation to pass in the presence of multiple source models. I would expect the following script to save a new event and organiser, but instead it says that event_name is not present.
What am I missing?
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rom'
gem 'rom-sql'
gem 'rom-rails'
gem 'activemodel'
gem 'sqlite3'
gem 'activesupport'
end
require 'rom'
require 'rom-rails'
`rm -Rf /tmp/romtest.sqlite`
ROM.setup(:sql, 'sqlite:///tmp/romtest.sqlite')
class Events < ROM::Relation[:sql]
end
class Organisers < ROM::Relation[:sql]
end
class CreateEvent < ROM::Commands::Create[:sql]
relation :events
register_as :create
result :one
associates :organiser, key: [:organiser_id, :id]
end
class CreateOrganiser < ROM::Commands::Create[:sql]
relation :organisers
register_as :create
result :one
end
class CreateEventWithOrganiser < ROM::Model::Form
commands organisers: :create, events: :create
input do
attribute :email
attribute :event_name
end
validations do
validates :event_name, presence: true
end
def commit!
command = organisers.create.with(
email: email,
) >> events.create.with(
name: event_name,
)
command.transaction do
command.call
end
end
end
ROM.finalize
rom = ROM.env
gateway = rom.gateways.fetch(:default)
migration = gateway.migration do
change do
create_table :organisers do
primary_key :id
column :email, String, null: false
end
create_table :events do
primary_key :id
column :name, String, null: false
column :organiser_id, Integer, null: false
end
end
end
migration.apply(gateway.connection, :up)
f = CreateEventWithOrganiser.build(
email: 'test#example.com',
event_name: 'Test Event'
)
# Unexpectedly fails
f.save
puts f.errors.full_messages
# => "Event name can't be blank"
Here's an updated version of your script which works:
require 'rom'
require 'rom-rails'
`rm -Rf /tmp/romtest.sqlite`
ROM.setup(:sql, 'sqlite:///tmp/romtest.sqlite')
class Events < ROM::Relation[:sql]
end
class Organisers < ROM::Relation[:sql]
end
class CreateEvent < ROM::Commands::Create[:sql]
relation :events
register_as :create
result :one
associates :organiser, key: [:organiser_id, :id]
end
class CreateOrganiser < ROM::Commands::Create[:sql]
relation :organisers
register_as :create
result :one
end
class CreateEventWithOrganiser < ROM::Model::Form
inject_commands_for :organisers, :events
input do
attribute :email
attribute :event_name
end
validations do
validates :event_name, presence: true
end
def commit!
validate!
return if errors.any?
command = organisers.create.with(
email: email
) >> events.create.with(
name: event_name
)
command.transaction do
command.call
end
end
end
ROM.finalize
rom = ROM.env
gateway = rom.gateways.fetch(:default)
migration = gateway.migration do
change do
create_table :organisers do
primary_key :id
column :email, String, null: false
end
create_table :events do
primary_key :id
column :name, String, null: false
column :organiser_id, Integer, null: false
end
end
end
migration.apply(gateway.connection, :up)
f = CreateEventWithOrganiser.build(
email: 'test#example.com',
event_name: 'Test Event'
)
puts f.save.result.inspect
# #<ROM::Commands::Result::Success:0x007fa92b589ea0 #value={:id=>1, :name=>"Test Event", :organiser_id=>1}>
The reason why it didn't work with commands is because this method will generate command objects for your form and set provided validations for each command, which will only work correctly if you used a single command. Otherwise same validator is used for each command which doesn't make sense. When you use inject_commands_for it will grab your own commands where validators are not set so you are free to handle validations yourself.
I think we should stop setting validators on commands which would make your original sample work but notice that you need to call validate! yourself.
I hope this helps.
I also created a gist showing how to do the same without a form: https://gist.github.com/solnic/3b68342482cf1414f719

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