Raise error from Sequel::Model if table does not exist? - ruby

I am starting to use Sequel for database connection handling in my Ruby application and hit a weird little snag. I created a model for my ETags table like so:
class ETag < Sequel::Model
end
Which should have gone out and found the etags table in my database, but it didn't. I think it was looking for e_tags instead, and created an empty model without any columns. The solution was to change it to this:
class Etag < Sequel::Model
end
Simple enough. However, I feel like my initial attempt should have raised an error. Is there a simple way to tell Sequel to raise an error when building a model if it can't find the underlying table in the database?

There currently is not a way to do this automatically. Trying to do it automatically would break many existing setups that do something like:
class ETag < Sequel::Model
set_dataset :etags
end

Related

Database connection too much with ActiveRecord::Base.establish_connection

I use multible databases with ActiveRecord. I must put establish_connection db in all models. But i want to call the connection of libraries file. While put establish_connection db in for all models Database connection count is too much . How can I do other methods?
My project is a Ruby on Sinatra.
Build a global hash of {db_name => connection_instance } for all possible connections you have and retrieve them from your models intelligently:
def get_or_establish_connection db
$connections[db] ||= establish_connection db
end
That way you’ll reuse all already established connections.
NB I wrote “global” because there is no way to suggest anything more robust without knowledge of your architecture details. In the real life one would put this hash as a class variable somewhere accessible from everywhere.
What we did in our projects that used multiple databases was creating one class per database, that establish the connection, and make models inherit from it. That way, only one connection is created per database.
class UsageTable < ActiveRecord::Base
self.abstract_class = true
establish_connection :usage
end
class User < UsageTable

Ruby sequel equivalent to ActiveRecord none

I'm looking for a way to replicate the behavior of none in Sequel. So far I haven't been able to find a way to create a dataset, or a dataset like thing, without tying it to a table.
At the moment I am just returning an enum but I would like to preserve the dataset API to not break any chaining.
E.g.
class User < Sequel::Model
end
User.none # => instance of dataset
Sequel has a null_dataset extension for this: http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/null_dataset_rb.html

Caching ActiveRecord model instance methods

Say I have a user model. It has an instance method called status. Status is not an association. It doesn't follow any active record pattern because it's a database already in production.
class User < ActiveRecord::Base
def status
Connection.where(machine_user_id: self.id).last
end
end
So I do this.
#users = User.all
First of all I can't eager load the status method.
#users.includes(:status).load
Second of all I can't cache that method within the array of users.
Rails.cache.write("user", #users)
The status method never gets called until the view layer it seems like.
What is the recommended way of caching this method.
Maybe this instance method is not what I want to do. I've looked at scope but it doesn't look like what I want to do.
Maybe I just need an association? Then I get the includes and I can cache.
But can associations handle complex logic. In this case the instance method is a simple query. What if I have complex logic in that instance method?
Thanks for any help.
Have You tried to encapsulate this logic inside some plain Ruby object like this (I wouldn't use this for very large sets though):
class UserStatuses
def self.users_and_statuses
Rails.cache.fetch "users_statuses", :expires_in => 30.minutes do
User.all.inject({}) {|hsh, u| hsh[u.id] = u.status; hsh }
end
end
end
After that You can use some helper method to access cached version
class User < ActiverRecord::Base
def cached_status
UserStatuses.users_and_statuses[id]
end
end
It doesn't solve Your eager loading problem, Rails doesn't have any cache warming up techniques built in. But by extracting like this, it's easily done by running rake task in Cron.
Also in this case I don't see any problems with using association. Rails associations allows You to submit different options including foreign and primary keys.

Where and how should I add this new 'non-rails-way' method in my Rails application

I've written a small method to query and retrieve from an MS SQL 2008 server and I am not sure where to put the code in my rails app.
The scenario:
I am writing a Ruby and Rails app with a connection to a legacy MS SQL 2008 server DB.
A lot is working as expected, which is nice.
For now I work off a copy of the legacy DB and I treat it as readonly. It's big (7000+ tables some of which have over 40 million records). I am using it 'as-is' and don't want to change any of the underlying schema.
I do want to extend some very server-specific functionality. For instance, I make use of:
thing = ActiveRecord::Base.connection.exec_query(my_query_string_here)
... and it works. The result is an array that contains a hash and I can get to the relevant hash value by using:
thing[0][""]
... which works.
So, I thought I should write a method to make this easier and I wrote:
Class Tool < ActiveRecord::Base
def self.queryRDW(x)
res=ActiveRecord::Base.connection.exec_query(x)
ret=res.to_hash
return ret[0][""]
end
end
and put it in config/initializers/tool.rb Unfortunately, webrick complains about the file during boot with the following cryptic error:
.../config/initializers/tool.rb:7: syntax error, unexpected keyword_end, expecting $end (SyntaxError)
I recognize that this is not an out-of-the-box rails-way of doing things, so please don't remind me. (My struggles remind me often enough)
My question:
Where should I put this code so that I can invoke it from within a controller or a view in my rails app? Does this need to be a new Class method or something else?
Many thanks!
Addendum:
I changed Class to class (doh!)
I moved tool.rb into lib/
I changed tool.rb to now be:
module Tool
def self.queryRDW(x)
res = ActiveRecord::Base.connection.exec_query(x)
res.to_hash[0][""]
end
end
but doing this in app/views/stats.html.erb
thing=queryRDW("mysql string")
gets me an 'undefined method error'
Addendum 2
I made the directory app/concerns and put tool.rb there.
When I use:
<%=queryRDW("myStringHere")%>
in:
app/views/stats.html.erb
I get:
undefined method `queryRDW' for #<#<Class:0x0000000378ccf8>:0x00000003c1ce58>
You need to lowercase the keyword class in line 1.
I'd also say that this class doesn't need to inherit from ActiveRecord::Base — and doesn't even really need to be a class — if it's simply a wrapper around exec_query. There's nothing "wrong" with this, but if you never intend to instantiate an object of this class, you could just create a simple utility module:
module Tool
def self.queryRDW(x)
res = ActiveRecord::Base.connection.exec_query(x)
res.to_hash[0][""]
end
end
You can save this file in a couple of places:
lib/tool.rb. If you're using Rails 3, you'll need to add (or uncomment) this line in config/application.rb:
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
app/concerns/tool.rb. This will automatically be detected by Rails 3.
I generally use app/concerns for tools that are entirely application-specific and lib for utilities that I might reuse among several different applications.
I wouldn't put this in config/initializers. This seems like code you'd put in app/models.
The error you're getting is syntax related, so double check the syntax.
To answer your question more directly, though, it's acceptable to put this stuff in your model if it's model related (in other words, part of your business domain). If it is something extraneous or orthogonal to your domain, I'd put it in lib.
Hope this helps.

ActiveRecord 3.1.0 multiple databases

I'm trying to upgrade the ActiveRecord gem to the latest 3.1.0 release and seeing a lot of exceptions being raised, I think it's due to how we handle multiple databases.
For each of our databases we specify a separate base class which inherits from ActiveRecord::Base, and call establish_connection in there. There are no cross-database relations. This has worked fine for us up until now.
Having upgraded to ActiveRecord 3.1.0 I'm seeing that it fails with an ActiveRecord::ConnectionNotEstablished exception, when traversing relations (i.e. it will successfully pull a single entity or set of them from the DB, but fails when navigating to a related class).
The top line of the backtrace is C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.1.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in 'retrieve_connection', so I dug into this a little. The method is defined as follows:
def retrieve_connection(klass) #:nodoc:
pool = retrieve_connection_pool(klass)
(pool && pool.connection) or raise ConnectionNotEstablished
end
My simple test (puts Customer.first.address) calls retrieve_connection 3 times. Twice with Customer as the klass parameter, and once with ActiveRecord::Base as the parameter - which is when it fails as establish_connection has not been called for ActiveRecord::Base.
To the actual question then - is there a new recommended way of handling multiple database connections in ActiveRecord? If so, what is it?
If not, what could be causing this problem?
I ran into the same issue yesterday while upgrading to ActiveRecord 3.1.0. I can't speak to whether there is a new recommended way of handling multiple database connections in ActiveRecord 3.1, but I did find a way to unblock myself.
It appears a connection must now be established on ActiveRecord::Base in order for it to determine the table name lengths/rules of the adapter. Along with the rest of my connections established in my database initializer, I now also have an ActiveRecord::Base connection established to one of my DBs (it doesn't matter which one).
I'd like to think there's a better solution to be found, but I'm happy to be unblocked for now.
I am using this solution - What I was seeing was that when establish_connection was called in each of the OtherDb classes - there seemed to be alot of overhead reloading table definitions and I would randomly see issues every time the class def was reloaded.
# The idea here is to specify that a given model should use another
# database without having to change the entire inheritance hierarchy
# declare model for table in primary connection
class Bar < ActiveRecord::Base
# assume we have logic here that we don't want to refactor into a module
# but we do want to inherit in OtherDb::Bar
end
module Foo
# base model in Foo namespace - uses another db
class BaseConnection < ActiveRecord::Base
# OtherDb::Title.database contains a db config hash
# This would probably go in the initializers
establish_connection OtherDb::Title.database
end
# module used to override db connection
module OtherDb::Base
def retrieve_connection
# connection_handler.retrieve_connection(self) # normal behavior
connection_handler.retrieve_connection(Foo::BaseConnection) # use db from Foo::BaseConnection
end
end
# Foo::Bar is identical to ::Bar but is in another db
class Bar < ::Bar
extend OtherDb::Base
end
end

Resources