Ruby sequel equivalent to ActiveRecord none - ruby

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

Related

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

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

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.

ORM for Ruby that able to generate Model/Migration scripts from existing database

Is there ORM for Ruby that able to generate Model/Migration scripts from existing database?
i will use it with sinatra.
You can use Sequel's migrations to dump an existing schema (see "Dumping the current schema as a migration" down the linked page).
Also, I know that if you're on Postgresql or MS SQL Server you can dump the database into scripts, either as a schema or with data too. If the ORM you want to use doesn't have a to-migration facility (or even if it does) you can use those scripts, and even embed them within a migration (Sequel will accept standard SQL strings too, other ORM's probably can too).
Edit: generating models.
If you want to generate models, then Sequel has a reflection API. Something like this could get you started:
generator = ->(table) {
s = <<STR
require 'sequel'
class #{table} < Sequel::Model
# other stuff here
end
STR
}
DB.tables.reject{|name| name == :schema_info }
.each do |table|
File.new "app/models/#{table}.rb" do |f|
f.write generator.call(table)
end
end
To do the associations would be harder, but I think possible. Take a look at Database#foreign_key_list and Model association basics.
It's not an ORM, but there's a very old gem called magic_models which does this, not sure if it still works: http://magicmodels.rubyforge.org/

How to get activerecord associations via reflection

For normal columns, you can get at them via the columns class method. However, associations may be named something quite different if the foreign_key option is set in the relationship method. For example, given
class Post
has_many :comments, :foreign_key => :message_id # this is a contrived example
end
if I did Post.column_names I could get at message_id, but is there any way to get comments?
Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.
Post.reflections.keys # => ["comments"]
Here is an example of some of the information it can be used to access:
Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"
Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".
For future Googlers in Rails 4 the answer would now be:
Post.reflections[:comments].foreign_key # => "message_id"
Taken from here: https://stackoverflow.com/a/15364743/2167965
EDIT:
reflections, as of 4.2, now takes strings instead of symbols which is a fun bug to track down. If you want to keep using symbols you should switch to reflect_on_association(:assoc_name). Also note reflections are actually the public api which will keep reporting things like HABTM, even though it's all has many through under the hood. The reflections Rails is actually using are now in _reflections
For an ActiveRecord object I use:
object._reflections
So, I can manipulate the Hash returned. For instance:
object._reflections.keys.each do |key|
object.public_send(key).destroy_all
end
The above example delete all the relationships from database.

Is there a Ruby CSV parser that generates column getter methods?

I'm trying to generalize a data retrieval mechanism with Ruby, and can't seem to find a way to retrieve a CSV file and access one of the row's columns by using a dot operator like so:
Let's say I have a CSV table:
#some_file.csv
name,age
albert,13
And I create a FasterCSV table from it:
a = FasterCSV.new(File.open('some_file.csv'), :headers => :first_row)
Then, when accessing a row, I'd like to be able to say:
a[0].name
=> 'albert'
Instead of
a[0]['name']
=> 'albert'
Anyone know how to do that?
Well, if you don't find one, you can always monkey-patch FasterCSV::Row class, something like:
class FasterCSV::Row
def method_missing(m,*args)
if self.field?(m.to_s)
return self[m.to_s]
else
super
end
end
end
(Haven't tried the code myself.)
PS. As you are generalizing data retrieval mechanism, I assume that CSV is just one of several data sources you plan to support. The logical thing then would be to create a single wrapper class for each of your data sources, with some common interface (which might or might not use accessors for accessing row fields). But underneath it should still access CSV row usual way, using [] method. So, as Glenjamin already asked, why do you need this at all? ;)
The simplest answer would be.. why?
I'll assume its mostly as syntactic sugar, so here's a little monkeypatch that should do what it is you want:
class FasterCSV::Row
def method_missing(row)
field(row)
end
end
Note that any field names conflicting with existing Row methods wont work like this.

Resources