Using Rails 3.2.2 and ruby 1.9.3dev and mysql
I am new to ruby and rails. We have an existing database with a couple hundred tables. We would like to try out rails to see if it would be a positive change from PHP & ZendFramework.
Migrating data into another database is not an option for us because we have several other applications currently using this database. We wanted to "attach" a rails project to the existing database.
The part I am struggling is generating all the models from our existing database.
I seen a couple of older posts talking about some automated techniques including Magic Model Generator. While others talked about there is no way to do this, or you just have create them all manually.
I was not successful in generating models using Magic Model Generator (perhaps rails 2 only?)
Long ago, when we switched to ZendFramework, I wrote a quick script to analyze the database and generate all the model files for us. It would seem this would be a somewhat common scenario.
Note: We use ID instead of id and many have many foreign_key relationships.
So I wanted to ask the community what is the best (way/practice) to handle this?
It's not that difficult, just takes a bit more configuration. Here's a basic template for a model:
class YourIdealModelName < ActiveRecord::Base
self.table_name = `actual_table_name`
self.primary_key = `ID`
belongs_to :other_ideal_model,
:foreign_key => 'foreign_key_on_other_table'
has_many :some_other_ideal_models,
:foreign_key => 'foreign_key_on_this_table',
:primary_key => 'primary_key_on_other_table'
end
I am no expert and even had researched about this.
Without thinking to much first solution in my mind is to make the models and migrations according to the rails way so you don't have any problem, for example key and foreign key naming. If you have already some data you should migrate it to the rails db.
One reason to do this is that models are suppose not to be only data accessors but also contain the business logic
Related
I just ran into an interesting situation about relationships and databases. I am writing a ruby app and for my database I am using postgresql. I have a parent object "user" and a related object "thingies" where a user can have one or more thingies. What would be the advantage of using a separate table vs just embedding data within a field in the parent table?
Example from ActiveRecord:
using a related table:
def change
create_table :users do |i|
i.text :name
end
create_table :thingies do |i|
i.integer :thingie
i.text :discription
end
end
class User < ActiveRecord::Base
has_many :thingies
end
class Thingie < ActiveRecord::Base
belongs_to :user
end
using an embedded data structure (multidimensional array) method:
def change
create_table :users do |i|
i.text :name
i.text :thingies, array: true # example contents: [[thingie,discription],[thingie,discription]]
end
end
class User < ActiveRecord::Base
end
Relevant Information
I am using heroku and heroku-posgres as my database. I am using their free option, which limits me to 10,000 rows. This seems to make me want to use the multidimensional array way, but I don't really know.
Embedding a data structure in a field can work for simple cases but it prevents you from taking advantage of relational databases. Relational databases are designed to find, update, delete and protect your data. With an embedded field containing its own wad-o-data (array, JSON, xml etc), you wind up writing all the code to do this yourself.
There are cases where the embedded field might be more suitable, but for this question as an example I will use a case that highlights the advantages of a related table approch.
Imagine a User and Post example for a blog.
For an embedded post solution, you would have a table something like this (psuedocode - these are probably not valid ddl):
create table Users {
id int auto_increment,
name varchar(200)
post text[][],
}
With related tables, you would do something like
create table Users {
id int auto_increment,
name varchar(200)
}
create table Posts {
id auto_increment,
user_id int,
content text
}
Object Relational Mapping (ORM) tools: With the embedded post, you will be writing the code manually to add posts to a user, navigate through existing posts, validate them, delete them etc. With the separate table design, you can leverage the ActiveRecord (or whatever object relational system you are using) tools for this which should keep your code much simpler.
Flexibility: Imagine you want to add a date field to the post. You can do it with an embedded field, but you will have to write code to parse your array, validate the fields, update the existing embedded posts etc. With the separate table, this is much simpler. In addition, lets say you want to add an Editor to your system who approves all the posts. With the relational example this is easy. As an example to find all posts edited by 'Bob' with ActiveRecord, you would just need:
Editor.where(name: 'Bob').posts
For the embedded side, you would have to write code to walk through every user in the database, parse every one of their posts and look for 'Bob' in the editor field.
Performance: Imagine that you have 10,000 users with an average of 100 posts each. Now you want to find all posts done on a certain date. With the embedded field, you must loop through every record, parse the entire array of all posts, extract the dates and check agains the one you want. This will chew up both cpu and disk i/0. For the database, you can easily index the date field and pull out the exact records you need without parsing every post from every user.
Standards: Using a vendor specific data structure means that moving your application to another database could be a pain. Postgres appears to have a rich set of data types, but they are not the same as MySQL, Oracle, SQL Server etc. If you stick with standard data types, you will have a much easier time swapping backends.
These are the main issues I see off the top. I have made this mistake and paid the price for it, so unless there is a super-compelling reason do do otherwise, I would use the separate table.
what if users John and Ann have the same thingies? the records will be duplicated and if you decide to change the name of thingie you will have to change two or more records. If thingie is stored in the separate table you have to change only one record. FYI https://en.wikipedia.org/wiki/Database_normalization
Benefits of one to many:
Easier ORM (Object Relational Mapping) integration. You can use it either way, but you have to define your tables with native sql. Having distinct tables is easier and you can make use of auto-generated mappings.
Your space limitation of 10,000 rows will go further with the one to many relationship in the case that 2 or more people can have the same "thingies."
Handle users and thingies separately. In some cases, you might only care about people or thingies, not their relationship with each other. Some examples, updating a username or thingy description, getting a list of all thingies (or all users). Selecting from the single table can make it harding to work with.
Maintenance and manipulation is easier. In the case that a user or a thingy is updated (name change, email address update, etc), you only need to update 1 record in their table instead of writing update statements "where user_id=?".
Enforceable database constraints. What if a thingy is not owned by anyone? Is the user column now nillable? It would have to be in the single table case, so you could not enforce a simple "not nillable" username, for example.
There are a lot of reasons of course. If you are using a relational database, you should make use of the one to many by separating your objects (users and thingies) as separate tables. Considering your limitation on number of records and that the size of your dataset is small (under 10,000), you shouldn't feel the down side of normalized data.
The short truth is that there are benefits of both. You could, for example, get faster read times from the single table approach because you don't need complicated joins.
Here is a good reference with the pros/cons of both (normalized is the multiple table approach and denormalized is the single table approach).
http://www.ovaistariq.net/199/databases-normalization-or-denormalization-which-is-the-better-technique/
Besides the benefits other mentioned, there is also one thing about standards. If you are working on this app alone, then that's not a problem, but if someone else would want to change something, then the nightmare starts.
It may take this guy a lot of time to understand how it works alone. And modifing something like this will take even more time. This way, some simple improvement may be really time consuming. And at some point, you will be working with other people. So always code like the guy who works with your code at the end is the brutal psychopath who knows where you live.
I have an existing legacy Firebird database with nonstandard table and field names.
I would like to write a Sinatra app that can access it and display information. I've seen stuff like dm-is-reflective that appears to work when a database has proper naming conventions, but how do I use DataMapper (or ActiveRecord whichever is the easiest) to access those tables?
For example, assuming I had these two tables:
Bookshelfs
shelf_id: integer
level: integer
created: timestamp
Book
id: integer
id_of_shelf: integer
title: string
pages: integer
Something like with odd naming conventions that don't follow any set pattern and where one table's record might "own" multiple entries in another table even though there is not foreign_key assigned.
How would you set up datamapper (or activerecord) to communicate with it?
Look in to this gem to get setup with ActiveRecord on Sinatra:
https://github.com/bmizerany/sinatra-activerecord
As for how to define the relations, activerecord can do this easily.
class Book < ActiveRecord::Base
belongs_to :bookshelf, :class_name => 'Bookshelf', :foreign_key => 'id_of_shelf'
end
class Bookshelf < ActiveRecord::Base
has_many :books, :class_name => 'Book', :foreign_key => 'id_of_shelf'
end
Assuming you figured out how to connect to your legacy database using ActiveRecord's Firebird adapter, the next thing I would do is define a view on top of each table, e.g.
CREATE VIEW books AS SELECT * FROM Book;
CREATE VIEW bookshelves AS SELECT * FROM Bookshelfs;
This way you can simply define models Book and Bookshelf in ActiveRecord as per usual and it will find everything in the right place inside the database.
Is it possible with datamapper to generate the models from an existing database schema? So, to do the inverse of a migration, which takes the models and generate the sql. What I want is given a database schema generate the models.
try to check https://github.com/yogo/dm-reflection or any of its forks ..
At last, I found that till now the best solution is to use dm-is-reflective plugin: https://github.com/godfat/dm-is-reflective.
It doesn't generate the code for DataMapper models reflecting an existing database schema, but its properties access methods are automatically available (as long as you keep using this plugin, of course).
Here is an example of use:
require 'data_mapper'
require 'dm-is-reflective'
DataMapper.setup(:default, "postgres://user:pwd#localhost/db")
class Table
include DataMapper::Resource
is :reflective #activate dm-is-reflective
reflect #reflects eeach property. You can be more specific (look at plugin documentation)
end
DataMapper.finalize
#Even if no field is defined, all of them are accessible
entry = Table.first(nil, {:id => 469})
print entry.anotherField
Recently i added PostgreSQL to my application which was already running on MySQL, now application is running on two databases. I was able to establish associations between the tables present in different database and its working fine. Today i added a search feature in a page which uses tables present in two databases and its throwing an error. Spent all day trying to figure out the bug but didn't succeed. Please look into the associations,code and help me correct it.
I have 4 tables:-
Company(mysql)
Location(mysql)
Report(PostgreSQL)
Report_category(PostgreSQL)
model - company.rb
establish_connection Rails.env+"_postgres"
has_many :reports
establish_connection Rails.env
belongs_to :location
location.rb
has_many :companies
report.rb
establish_connection Rails.env
belongs_to :company
establish_connection Rails.env+"_postgres"
belongs_to :report_category
report_category.rb
establish_connection Rails.env+"_postgres"
has_many :report
Now from view i pass the search parameters and in my reports_controller i write
#reports = Report.where("companies.name like ? and report_category.name ?", params[:company], params[:category]).includes(:company, :report_category)
after executing this line i'm getting the below error
ActiveRecord::StatementInvalid: PGError: ERROR: relation "companies" does not exist
but
Company.where("location.name like ?", params[:location]).includes(:location)
or
Report.where("report_categories.name like ?", params[:category]).includes(:report_category)
works perfectly fine. I only get the error if i search using two databases. Please do help
First I want to second the suggestion in the comments that you move everything onto one db. This saves you a lot of complexity down the road. However if you really can't do this, there are a couple ways you can access the MySQL tables from within PostgreSQL, and this would be a second-class solution to a full migration, but it would work.
In PostgreSQL 9.1 and higher you can do read-only queries using foreign data wrappers for MySQL. In earlier versions you can use David Fetter's DBI-Link project to make the connection.
These then allow you to present your data as a unified database to your applications.
I've configured my database.yml to point to my existing mysql database
how can I generate models from it?
rails generate model existing_table_name
only gives an emty model..
You can try Rmre. It can create models for existing schema and it tries to create all relationships based on foreign keys information.
A Rails model doesn't show your fields, but you can still use them. Try the following. Assuming you have a Model named ModelName and a field called "name", fire up the Rails console and type:
ModelName.find_by_name('foo')
Given a name that exists in the DB, you should see results.
Rails doesn't infer relationships though, but if your database follows Rails conventions they are easily added.
Update
I've noticed this particular lack of explicitness ("magic") is a source of confusion for newbies to Rails. You can always look in schema.rb to see the models and all the fields in one place. Also, if you would prefer to see the schema for each model in the model file, you can use the annotate_models gem, which will put the db schema in a comment at the top of the model file.
Your answer is:
$ rake db:schema:dump
That will set a new db/schema.db to create a schema of your DB.
ActiveRecord doesn't parse a schema definition. It asks the DBM for the table defs and figures out the fields on the fly.
Having the schema is useful if you are going to modify the tables via migrations.
Schema Dumping and You will help you dump it to use as a reference for building migrations.
ActiveRecord makes some suppositions about the table naming and expects an id field to be the primary key with a sequential number as the type. Having the migrations would help you to refactor the tables and/or fieldnames and types, but you can do those same things via your DBM's command-line. You don't really have to follow ActiveRecord's style but doing so helps avoid odd errors and lets AR infer things to make your life easier.
Could try Magic Model Generator
Take a look at rare_map gem.
https://github.com/wnameless/rare_map
It works both on Rail 3 and 4.