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.
Related
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]
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.
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.
Given I have the following migration:
Sequel.migration do
up do
alter_table :users do
add_column :is_admin, :default => false
end
# Sequel runs a DESCRIBE table statement, when the model is loaded.
# At this point, it does not know that users have a is_admin flag.
# So it fails.
#user = User.find(:email => "admin#fancy-startup.example")
#user.is_admin = true
#user.save!
end
end
Then sequel does not automatically reload the table structure (see comment inline).
I am using this ugly hack to work around it:
# deep magic begins here. If you remove a single line, it will
# break the migration.
User.db.schema("users", :reload => true)
User.instance_variable_set(:#db_schema, nil)
User.columns
User.new.respond_to?(:is_admin=)
sleep 1
Is there a better way?
Much simpler than your hack is this hack: (re)set the dataset to the table name:
User.set_dataset :users
Seen in action:
require 'sequel'
DB = Sequel.sqlite
DB.create_table :users do
primary_key :id
String :name
end
class User < Sequel::Model; end
User << { name:"Bob" }
DB.alter_table :users do
add_column :is_admin, :boolean, default:false
end
p User.first #=> #<User #values={:id=>1, :name=>"Bob", :is_admin=>false}>
p User.setter_methods #=> ["name="]
User.set_dataset :users # Make the magic happen
p User.setter_methods #=> ["name=", "is_admin="]
#user = User.first
#user.is_admin = true
#user.save
p User.first #=> #<User #values={:id=>1, :name=>"Bob", :is_admin=>true}>
Note that there is no Sequel::Model#save! method; I changed it to save so that it would work.
-----UPDATE-----
Well, seems that the problem was in last.id. When database is created works OK, but when not fails. Now the question is different: How can I create a field using the id from the same row?
--------ORIGINAL------
I'm working with active record in pure ruby (without Rails), and I'm literally getting crazy with this.
This is my code
class Enviroment < ActiveRecord::Base
#self.table_name = 'enviroments'
self.connection.create_table(:enviroments, :force=>true) do |t|
t.column :name, :string, :default=>'env-'+ (last.id-1).to_s
t.column :ssh, :string, :default=>nil
end
end
and here the error:
ActiveRecord::StatementInvalid: Could not find table 'enviroments'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.2.3/lib/active_record/connection_adapters/sqlite_adapter.rb:465:in `table_structure'
if I useself.table_name = 'enviroments' still not working. I've updated the gems and neither.
I'm newbie with ruby and databases, but I can't understand this problem, I think this same code worked in the past :S
Your code to create the table (very odd to have that in the model by the way) is calling last.id, and of course to call last the table must already exist.
Because you're passing :force => true to create_table you'll actually destroy the table if it already exists.
You could probably make your code work if you stashed the value of last.id in a local variable before the call to create_table but I don't understand why you are creating tables like this.
Finally, this was my solution:
class Enviroment < ActiveRecord::Base
after_create :create_default
private
def create_default
if name == nil
s = 'env-' + self.id.to_s
self.name = s
self.save
end
end
end
class CreateSchema < ActiveRecord::Migration
create_table(:enviroments, :force=>true) do |t|
t.column :name, :string, :default=>nil
t.column :ssh, :string, :default=>nil
end