NameError Uninitialized Constant in rails for existing table - sql

I'm a bit stuck on a problem here in Rails that I feel may have a simple solution.
I have a class called "CircuitVw" which looks like the following
class CircuitVw < ActiveRecord::Base
self.table_name = 'mvw_circuits'
self.primary_key = :serv_item_id
Inside the controller, I've been able to pull back data using the following format
CircuitVw.all().order("customer_name DESC").each do | circuit |
#customer[ "#{circuit.customer_name}" ] = circuit.psr
end
However, when I try and access the table written this way, I get an uninitialized constant
MVW_CIRCUITS.where("activity_ind IN ( 'Pending', 'In Progress')").order("document_number DESC").each do | circuit |
#psr[ "#{circuit.psr} - #{circuit.customer_name}" ] = circuit.psr
end
Even though I can say something like
SELECT * FROM MVW_CIRCUITS
And return the entire table in the console for my staging environment.
What am I doing wrong here?
The table exists in the schema as
create_table "mvw_circuits", id: false, force: true do |t|
for reference.
Thanks for any insights you might have! Maybe I'm forgetting something dumb. Appreciate any and all help.

You have to use CircuitVw to access or refer to the table mvw_circuits. You specified that in the CircuitVw class. So MVW_CIRCUITS is an uninitialized constant.
Try this one
CircuitVw.where("activity_ind IN ('Pending', 'In Progress')")

Related

Rails checkbox not storing correct value

I'm creating a form using Ruby Rails. It has a checkbox that when checked denotes the entry should be hidden (true or bit 1. vs false/bit 0), however, when I submit the checkbox I receive an error:
Mysql2::Error: Data too long for column 'hidden_status' at row 1: INSERT INTO `entries` ( 'hidden_status') VALUES (x'30')
The schema for entries and hidden_status is:
t.binary "hidden_status", limit: 1
The checkbox is:
<%= newEntry.check_box(:hidden_status,{checked:true},1,0)%>
I suspect this has something to do with the datatype being "bit"? However I'm not sure as I'm new to Ruby Rails and from what I looked up BIT is the only way to do a boolean/true vs false value in SQL. Looks like the value is coming up as as x'30'. Not sure what that means. Is there a way to allow the checkbox to capture 1 or 0?
Also, the parameters in the error shows that the value of the checkbox always returns 0 whether the box is checked or not. Not sure if this is a separate issue or related to the error.
MySQL still as of 2020 has not implemented a real boolean column type. But it does let you declare tables with BOOLEAN/BOOL:
CREATE TABLE tasks (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
completed BOOLEAN
);
Whats actually created is a tiny_int(1) column. Although the current advice is to use a bit column I doubt the Rails adapter knows how to map this to booleans.
You can just create the migration in Rails like you would in a real grown-up database (laughs in Postgres):
class CreateTasks < ActiveRecord::Migration[6.0]
def change
create_table :tasks do |t|
t.string :title
t.boolean :completed
t.timestamps
end
end
end
schema.rb will still list it as a boolean column as its an abstract polyglot representation of the database schema but MySQL will store it as tiny_int(1) and the database driver will take care of casting it to a boolean so you don't have to deal with 1 and 0 in Rails.

activerecord - Time format

This has got to be extremely simple but I'm banging my head against the wall trying to find an answer. I want to find the last updated record using the instance method shown below.
class Subject < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
def get_last_assignment_date
#last_date = self.assignments.select("date_assigned").last
#last_day = #last_date.wday
end
Where my assignments model looks like this:
create_table "assignments", :force => true do |t|
t.date "date_assigned"
<snip>
But Rails returns the following error for get_last_assignment_date:
undefined method `wday' for #<Assignment date_assigned: "2012-08-30">
I need to convert the value returned by active record to a Time format that Ruby can handle but I can't figure out how to do it and it seems to be so easy that no one has even bothered to write how to do it. I would greatly appreciate it if someone could point me in the right direction.
This:
self.assignments.select("date_assigned").last
returns an Assigment object, not a Time object.
So, instead of:
#last_day = #last_date.wday
you have to do:
#last_day = #last_date.date_assigned.wday
You may be aware of this, but just in case: select("date_assigned").last doesn't give you the latest date. You have to use order:
self.assignments.order(:date_assigned).last
Of course if the most recently created object is also the one with the latest date_assigned then it doesn't matter.

Change Attribute of another table

I have the table "tools" and "lend".
Im using Rails3 and when i create a lend i would like it change the attribute status of the tool to 'U'.
Would this is possible?
i tried on the model lend
after_save :change_status
def change_status
tools.update_attribute(status, 'U')
end
i tried too, on the same model:
after_save :change_status
def change_status
self.tool.update_attribute(status, 'U')
end
No success or warning on debug log.
Sugestions?
Thanks! :)
What is the relationship between lend and tool? If Lend has_many tools, you will have to do something like this:
def change_status
tools.each { |tool| tool.update_attributes(status: 'U') }
end
Note also that I am using update_attributes because update_attribute (singular) will be deprecated soon.
BTW, you should create a method in Tool to update the attribute, the Lend model should not be aware about how to set a tool as loaned. Something like
def loaned!
update_attributes status: 'U'
end
Firstly, I assume that your Lend model has_many :tools
In order to be able to do something like tool.update_attribute you'll need to work with the accepts_nested_attributes_for
Take a look at these links and they will probably set you on the right path:
RailsCasts #196 Nested Model Form Part 1
Active Record Nested Attributes
Hope this helps.

How to make attribute setter send value through SQL function

I'm trying to make an attribute setter in an ActiveRecord model wrap its value in the text2ltree() postgres function before rails generates its sql query.
For example,
post.path = "1.2.3"
post.save
Should generate something like
UPDATE posts SET PATH=text2ltree('1.2.3') WHERE id = 123 # or whatever
What's the best way of doing this?
EDIT: To achieve exactly what you are looking for above, you'd use this to override the default setter in your model file:
def path=(value)
self[:path] = connection.execute("SELECT text2ltree('#{value}');")[0][0]
end
Then the code you have above works.
I'm interested in learning more about ActiveRecord's internals and its impenetrable metaprogramming underpinnings, so as an exercise I tried to accomplish what you described in your comments below. Here's an example that worked for me (this is all in post.rb):
module DatabaseTransformation
extend ActiveSupport::Concern
module ClassMethods
def transformed_by_database(transformed_attributes = {})
transformed_attributes.each do |attr_name, transformation|
define_method("#{attr_name}=") do |argument|
transformed_value = connection.execute("SELECT #{transformation}('#{argument}');")[0][0]
write_attribute(attr_name, transformed_value)
end
end
end
end
end
class Post < ActiveRecord::Base
attr_accessible :name, :path, :version
include DatabaseTransformation
transformed_by_database :name => "length"
end
Console output:
1.9.3p194 :001 > p = Post.new(:name => "foo")
(0.3ms) SELECT length('foo');
=> #<Post id: nil, name: 3, path: nil, version: nil, created_at: nil, updated_at: nil>
In real life I presume you'd want to include the module in ActiveRecord::Base, in a file somewhere earlier in the load path. You'd also have to properly handle the type of the argument you are passing to the database function. Finally, I learned that connection.execute is implemented by each database adapter, so the way you access the result might be different in Postgres (this example is SQLite3, where the result set is returned as an array of hashes and the key to the first data record is 0].
This blog post was incredibly helpful:
http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/
as was the Rails guide for plugin-authoring:
http://guides.rubyonrails.org/plugins.html
Also, for what it's worth, I think in Postgres I'd still do this using a migration to create a query rewrite rule, but this made for a great learning experience. Hopefully it works and I can stop thinking about how to do it now.

Rails - changed a table name, now tests won't run

Using Rails 3, I've changed the name of a table in the model like this:
# app/models/product.rb
class Product < ActiveRecord::Base
set_table_name "items"
end
But when I try setting up tests, I get the following error:
Started
E
Finished in 0.027396 seconds.
1) Error:
test_the_truth(CustomerTest):
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'project2_test.products' doesn't exist: DELETE FROM `products`
1 tests, 0 assertions, 0 failures, 1 errors
Any idea how I can let it know about Products?
OK found the answer here:
http://www.missiondata.com/blog/systems-integration/80/rails-fixtures-with-models-using-set_table_name/
Had to change the name of the Fixture yml file from Products to Items.
Rather than alter the class directly, you should create a migration. This will allow Rails to smoothly change the database, and allow any others working on the project to change their database in the same manner.
Write a change method which uses rename_table.
class RenameProductsToItems < ActiveRecord::Migration
def change
rename_table :items, :products :string
end
end