Rails codebase scaling and changing on ActiveRecord - ruby-on-rails

I'm currently rewriting our rails server code since many months have passed since our project began and there's a lot of dead code. We needed to migrate from Rails 3.2.12 to Rails 4. The issue is we need to rename some of our models and also need them to connect to the same PostgresSQLdatabase (ActiveRecord) and Redis objects.
For example:
#api v1
class ModelA < ActiveRecord::Base
include Redis::Objects
...
attr_accessible :id, :text_body
...
set something_redis_ids #redis object
...
end
To:
#api v2
class RenamedModelB < ActiveRecord::Base
include Redis::Objects
...
attr_accessible :id, :text_body
...
set something_redis_ids #redis object
...
end
That is I want to RenamedModelB to have its id andtext_body from PSQL as well as the something_redis_ids from redis to point to the exact same items as in ModelA. How do we accomplish this? We prefer to basically rewrite the codebase from scratch so don't really want to build on top of our old, ugly api v1.
Thanks for taking the time to read.

Is your question about the existing table names not matching your new class name? IF so, you can simply override it:
class Product < ActiveRecord::Base
self.table_name = "PRODUCT"
end
http://guides.rubyonrails.org/active_record_basics.html#overriding-the-naming-conventions

Related

Rails autoloading and gem classes

So I've got a gem which contains an ActiveRecord Model
# one of 30 or so models used by a suite of applications
class MyModel < ActiveRecord::Base
# some library code
end
# in Rails app, I want to add some behavior to this model using good old ruby class reopening
class MyModel < ActiveRecord::Base
scope :active, { where active: true }
end
The problem is that my app-native version of this model is only autoloaded thanks to Rails. Since it was loaded by the library and the constant is registered, it will never go to the local model to add the locally defined behavior.
Short of having an initializer with a hard-coded list of requires to the local version of the model, how might I get rails to marry the two definitions of the class to end up with one class that has all the behavior?
The simplest solution would be to:
In your gem, change the model name to something more generic (MyModelTemplate) and make it abstract:
class MyModelTemplate < ActiveRecord::Base
self.abstract_class = true
# some library code
end
Make your real model inherit MyModelTemplate:
class MyModel < MyModelTemplate
end

Ruby on Rails Activemodel with Associations

Acutally i face some hard exercises in computer science (hard for me i think, haha).
We're doing some basic stuff with Ruby on Rails an i have to open a csv file to get additional information on my 'User' model which is a normal rails scaffold.
So at the moment i open the csv file in my users_controller.rb file and search for the right row an add them to an instance variable.
But i wonder if i can write a class that acts like an ActiveRecord Model. So i change the code to use ActiveModel. But as i read in some google results, ActiveModel can't make use of ActiveRecord like associations. But it would great to have them.
So i hope you can help me. How can i provide my model with ActiveRecors like associations?
Greetings
Melanie
It's absolutely right that the CSV file should be represented as a model, as it's data.
However, trying to incorporate Active Model sounds tricky and would almost certainly require a great deal of hacking or monkey patching.
Unless you really need associations to other models, I would create a standalone class (i.e. not inheriting from ActiveRecord::Base) in the models directory, and put the logic for parsing the CSV in there:
class User
attr_accessor :name, :email, ...
def initialize(name,email,...)
# set data
end
def self.find(param_for_search)
# Parse CSV file, find line you want
# return a User instance
self.new(name, email)
end
end
I don't know exactly how your system works, but this way you can make it behave in a similar way to Active Model stuff. You can add similar class methods and each instance method represents a CSV file row.
Every time , when you are creating your own model , it is inheritance of ActiveRecord :
class Project < ActiveRecord::Base
attr_accessible :content, :name, :user
end
Then you can tell your model to have many (let's say) Project's Tasks , which creates an association . Please , provide an example of your app's logic.
Here is a quote from RailsCasts.com :
"In Rails 3 the non-database functionality of Active Record is extracted out into Active Model. This allows you to cleanly add validations and other features to tableless models."
There is also a nice description how to add functionality in you model by adding modules .
I understand, that using ActiveRecord to use an non database source is difficult, but i think it would be vewy charming if i could write something like this:
user.worktimes.first.value
in my view and get the information like it is a database table. I visit railscast.com an i found a episode where this ist discussed. But i would like to digg deeper in this. Are there any further ressources i could read?
As i understand, ActiveModel does not support associations? I wonder why associations wasn't moved to ActiveModel as it is a very useful thing. :)
So here is my code, that i was working on:
User-Model:
class User < ActiveRecord::Base
attr_accessible :department_id, :name
belongs_to :department
end
Department-Model:
class Department < ActiveRecord::Base
attr_accessible :name
has_many :users
end
And here is my CSV Model, that i created:
class Worktime
attr_accessor :user_id,:date,:value
def initialize(params)
dir = Rails.root.join('app', 'models', 'worktimes.csv').to_s
source = File.open(dir,'r')
while(line=source.gets)
data = line.split(';')
if data[0] = params[:user_id] && data[1] = params[:date]
#value = data[2]
end
end
end
end
I am very thankful for your help as its my first time using rails.

Rails inheritance for classes of same behaviour but different attributes

I have been researching on the best approach for my problem which I originally had implemented as a single table inheritance but am deeply concerned about the scalability, as potentially will have thousands of columns in the table.
So the problem is I would like to have products which the methods of each are exactly the same the only difference being the attributes each one contains. It seems that in this situation that mutli-class inheritance (not supported natively in rails?) would be the best approach or some sort of polymorphic associations.
I want to work towards the following
#product.rb
Class Product < ActiveRecord::Base
attr_accessible :title .....
def to_s # some arbitrary method used by all extending classes
....
end
end
#book.rb
class Book < Product
attr_accessible :author...
end
So I want the book to inherit the methods from product and not for the product to know about the attributes required by each subclass. And if possible get all of the products through one query.
I need to know the best way of approaching this, and if I am doing it completely wrong, please note the code written above is just for example to simplify my problem.
What you can do is create a module and include it in several different models.
First, create a file in your lib directory
i.e.) my_module.rb
module MyModule
def full_name
"#{first_name} #{last_name}"
end
end
Then, make sure the module is loaded when your Rails App starts:
In config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
Finally, include it in your models:
i.e.) app/models/thing.rb
class Thing < ActiveRecord::Base
attr_accessible :first_name, :last_name
include AdditionMod
end
You can test it in the console:
#thing = Thing.create(first_name: "Awesome", last_name: "Module")
#thing.full_name
=> "Awesome Module"
Found out that I can use H-store in conjunction with postgres that allows me to have a column that contains a schema less hash that can be used with the power of postgres (for an example take a look at http://hstoredemo.herokuapp.com/)

Rails: dynamic environmental settings without magic numbers

Short version: Where should I store environment-specific IDs? ENV['some-variable']? Somewhere else?
Long version:
Let's say I have a model called Books and a book has a Category. (For the sake of this question, let's say a book only has one category.)
class Book < ActiveRecord::Base
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :books
end
Now let's say one category is called 'erotica.' And I want to suppress erotica books in my type ahead. That seems straight forward. But in production and in development 'erotica' has a different ID. I don't want my code to be ID dependent. I don't want it to be string dependent (in case 'erotica' is renamed pr0n or whatever).
I think I should have something like
def suppress_method
suppress_category_id = look_up_suppression_id
...
end
but where should 'look up' look?
Thanks!
Taking this approach will be brittle, what if you want to suppress multiple categories? Erotica and Politics? The best design here is for you to actually add 'suppressed' as a boolean to category in a migration, and maintain that in your application's administration interface. After you've done that you can add a named scope like:
class Category < ActiveRecord::Base
named_scope :not_suppressed, :conditions=>{:suppressed=>false}
# or for rails 3
scope :not_suppressed, where(:suppressed=>false)
end
Then just update your type ahead code to do:
Category.not_suppressed.find ...
Rather than
Category.find

How to best handle per-Model database connections with ActiveRecord?

I'd like the canonical way to do this. My Google searches have come up short. I have one ActiveRecord model that should map to a different database than the rest of the application. I would like to store the new configurations in the database.yml file as well.
I understand that establish_connection should be called, but it's not clear where. Here's what I got so far, and it doesn't work:
class Foo < ActiveRecord::Base
establish_connection(('foo_' + ENV['RAILS_ENV']).intern)
end
Also, it is a good idea to subclass your model that uses different database, such as:
class AnotherBase < ActiveRecord::Base
self.abstract_class = true
establish_connection "anotherbase_#{RAILS_ENV}"
end
And in your model
class Foo < AnotherBase
end
It is useful when you need to add subsequent models that access the same, another database.
Heh. I was right! More cleanly:
class Foo < ActiveRecord::Base
establish_connection "foo_#{ENV['RAILS_ENV']}"
end
Great post at pragedave.pragprog.com.

Resources