rails 3.1 engines and databases - ruby-on-rails

Can rails 3.1 engines have their own databases and at the same time also have access to the database of the main app, for example for user authentication
How can i configure this if possible?
thanks

Yes, they can. I have built engines that use a separate sqlite3 database. This way all the engine's functionality and data is isolated. Remove the engine, remove the database, and everything is gone without leaving a trace.
First of all it's preferred that you generate a mountable engine. This creates a namespace and isolates the engine from your main app. It's not a requirement, but a best practice. I assume you've done in the examples that follow.
At one point you are going to generate a model inside your engine. In the engine root path, type something like this:
$ rails generate resource Post
This will generate the Post controller, model and route. Everything's perfect except for the database migration. You're going to delete this. This migration is useless if you want to keep your data separate. The only goal of migrations inside engines is to have them copied over to the main app's database. So go ahead and get rid of it:
$ rm -r db
Now hook up your root route and controller, like usual.
There's one more change to make inside the model, to make it connect to a separate database.
module YourEngine
class Post < ActiveRecord::Base
establish_connection :adapter => 'sqlite3', :database => 'db/your_engine.sqlite3'
end
end
This way the engine's model will not use the main database, but the one you define. The key to understand is that the database file does not live inside the engine! This database file lives inside the host application. Since you are keeping everything separate, you must create this database by hand. Using the sqlite3 command-line tool and a hand-crafted create statement is quickest:
$ cd "the root dir of the host rails app"
$ sqlite3 db/your_engine.sqlite3
from where you create the table:
CREATE TABLE your_engine_posts (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name varchar(255) NOT NULL DEFAULT '', body text, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL);
Presto! Now it's just a matter of mounting the engine inside your app, boot it and it should all be ready to roll. Obviously now that your engine has a separate database, it's no use working with migrations. You will have to update the schema by hand.

If you're worried about table names clashing with the app you can use the 'isolate_namespace' method. This will prefix all your table names with the namespace of your Engine.
Rails Casts just had a good tutorial which uses this, you should check it out.
http://railscasts.com/episodes/277-mountable-engines

Yes they can.
I wrote a guide on this here
http://railsforum.com/viewtopic.php?id=42143

Related

Rails Engine: Create dummy model for relations?

I am trying to make a Rails Engine that can be plugged into my applications and manage friendships between users. To do that, all the logic dealing with friend requests, acceptance, etc, is going to live in a Rails Engine.
When I create my Friendship model, it needs a belongs_to relation for two Users (two friends). But, I don't want to tie a user to this engine. I want this engine to work generically with any User an application has established.
What technique does one use to create a dummy User that is never to be included in the host application? (I want to avoid a migration of the engine pulling in this dummy User.)
Update:
I removed the second question, pertaining to how to then override the engine's User with the host app's User. I found the answer to that in the guides (http://edgeguides.rubyonrails.org/engines.html#configuring-an-engine).
tl;dr
cd into engine's dummy app root
run rails g model User
run rake db:migrate
Discussion
I came here looking for an answer, but seeing how there were no answers, I will share how I ended up solving this.
When creating a mountable Rails engine (via something like rails plugin new . --mountable --dummy-path=spec/dummy), Rails will generate a "dummy" app for your engine that will serve as the main app an engine would normally be required into.
Us RSpec users use the "--dummy-path" directive and put the dummy app in /spec folder, but for you it may be elsewhere. Find where it is and cd into that dummy app's root.
Once inside the dummy app, call rails g model User to generate a User model for the dummy app. Run rake db:migrate to add the table.
Now you have a placeholder User model that should function acceptably in tests as an association.
You may want to define some mock methods on User, do so in the model definition file located in /path/to/dummy/app/models/user.rb
Naturally, you can make a full-fledged model with associations and logic instead of just a placeholder right there in dummy.
Migrations and code in dummy app are not used when an engine is included in an app,as rake railties:install:migrations will show.
This might be a bit hacky!
I have an app with several engines. Each engine needs to call a limited amount of functionality in the other engines.
For example, Engine1 and Engine2 don't depend on (require or load) each other. However, a model such as Engine1::User might need to call a selection of records using a scope called all_active from the Engine2::Department model. That's okay inside the context of the overall Rails app into which both engines are loaded as Gems.
The problem arises for the developer of Engine1 when they want Engine2::Department.all_active, and they don't have it.
The solution I am using is to create a "mocked model" (for want of a better phrase) in Engine2's test/dummy/app/models (or spec/dummy/app/models if you're using RSpec) folder.
Something like this will work in Engine1:
# spec/dummy/app/models/engine2/department.rb
require '../../app/models/engine2/department' if File.exist?('../../app/models/engine2/department')
module Engine2
class Department
unless Engine2::Department < ActiveRecord::Base
def self.all_active
[{ id: 1, name: 'Finance', active: true},
{ id: 2, name: 'Sales', active: true}]
end
end
end
end
Because this file is in the dummy app, it won't get found by the main Rails app, so it won't interfere there. It will only get loaded in the dummy rails app during development and testing.
FYI, the unless Engine2::Department < AR::Base detects if the Department model inherits from ActiveRecord already, and if it does, the enclosing code won't be loaded. This is a safety mechanism to prevent the class method all_active from being overwritten by the hard-coded sample data in the hash shown above.
If you have a lot of engines in your system, perhaps you should consider creating a git repo of an engine template that can be pulled into each engine (containing common code, etc).
Your sample data might benefit from being OpenStruct objects, so your hash keys can be accessed using dot notation. You could then write code such as #engine2_departments.first.name rather than #engine2_departments.first[:name].

Reverse Engineering (Generating) Tables or Database Schema from Models and Views in Ruby on Rails

Update: The Question is Still Open, any reviews, comments are always welcome
I am having an existing rails project in which some important files and directories has been missed.
project rails version (2.3.8) i found it in environment.rb
currently what i am having is
app
controllers (already fully coded)
helpers (already fully coded)
models (already fully coded)
reports (already fully coded)
views (already fully coded)
config ---> default configurations (already fully coded)
lib ---> contains nothing
public --> contains images and scripts (already fully coded)
script ---> contains server,runner,plugin,dbconsole....
app directory fully contains working state of codes, app/model contains more than 100 .rb files , so i assume it will be more than 100 tables
the mainly missing things are db directory, .gem file, rake file, doc, test, vendor, database,schema.rb and migrations
Note:
i don't have the table schema and database for that project
i am in Need to generate tables or complete database from models and views and
i am looking for reverse engineering kind of stuff for generating db schema from models or views
I am newbie to rails and i am from java background , in java by using hibernate there is an pojo(model in rails) to database option available, i am looking for similar kind of stuffs for rails , and my main aim to run that project , so guys please help me.
To recreate the database schema, it will take quite a bit of time.
You can get a lot of information about the database in the app/models, app/controllers app/views directory.
You should know that ActiveRecord does not require you to explicitly list all the attributes of a model. This has important implications - you can only infer what attributes you still have to add to the database, based on whether an attribute is referred to! This means doing this will be a bit of an ART. And there are no CLEAR steps to complete this work. But below are some rules which you can use to HELP you.
This is a BIG project, below are guidelines, rules and tips to help you. But be aware that this could take a long time, and be frustrating at times to get this done.
What Tables you need:
Each table will normally have a matching ActiveRecord::Base model. So in the app/models directory, check each file, and if the class inherits from ActiveRecord::Base, it is an extra table.
The table name is by default a pluralized snake case version of the name of the class.
class UserGroup < ActiveRecord::Base # for this class
the name of the table is user_groups. Notice it is plural, and instead of camel case, it is lowercase, with underscores to separate the words.
All these tables will have an "id" integer column. By default, the tables also have a "created_at", and "updated_at" column of type datetime.
Associations and foreign keys:
You can infer what foreign keys exist by the associations in the Models. All associations are explicitly listed, so this is not too hard.
For example:
class UserGroup < ActiveRecord::Base # for this class
belongs_to :category
This means that the user_groups table has a column named "category_id", which is a foreign key for the categories table.
This means that the Category model likely has an inverse relationship (but no extra column):
class Category < ActiveRecord::Base
has_many :user_groups
The main other association is the has_many_and_belongs_to association. Eg.
class A < ActiveRecord::Base
has_and_belongs_to_many :bs
end
class B < ActiveRecord::Base
has_and_belongs_to_many :as
end
This means that there is a join table to add called "as_bs" (as and bs are sorted alphabetically), with the foreign keys "a_id" and "b_id".
All foreign keys are integers.
Attributes
Ok, so that's the table associations. Now for the normal attributes...
You should check the app/views/user_groups/ or other similar app/views directories.
Inside you will find the view templates. You should look at the _form.html.erb templates (assuming it is .erb templates, otherwise it could be .haml etc templates).
The _form.html.erb template, if it exists, will normally have many of the attributes listed as form fields.
In the form_for block, check if it says something like f.text_field :name, it means there is an attribute/(column in the table) called "name". You can infer what type the column should be by what type of field it is. Eg. in this case, it is a string, so maybe a VARCHAR(255) is appropriate (referred to as string in Rails).
You might also need to infer what type is appropriate based on the name of the attribute (eg. if it mentions something like :time, then it is probably either of type Time or DateTime).
This may give you all the other attributes in the table. But in some cases, you might miss the attributes. If you find a reference to other attributes in the controller, eg. app/controllers/user_groups_controller.rb, then you should add that as a column in your table. You can leave this until the end when you test it though, because when you test it, if an attribute is missing, then it will throw a NoMethodError for the object of the relevant model. Eg. if it says that #user_group variable, of class UserGroup, is missing a method named title, then it probably is missing a column named "title" of type string.
Recreate your migration/database
Ok, so now you know what the database tables and column names and types should be.
You should generate/recreate a migration for your database.
To do this, just use the command rails generate migration RecreateTables.
Then you should find a file in db/migrate/???_recreate_tables.rb.
Inside, start writing ruby code to create your tables. Reference for this can be found at http://guides.rubyonrails.org/migrations.html.
But essentially, you will have something like:
class RecreateTables < ActiveRecord::Migration
def up
create_table :user_groups do |t|
t.string :name # adds a string (VARCHAR) column called "name"
t.text :description # adds a textarea type column called "description
t.timestamps # adds both "created_at" and "updated_at" columns for you
end
end
def down
drop_table :products # this is the reverse commands to undo stuff in "up"
end
end
To recreate your Gemfile:
Start by adding a default Gemfile. This can be done by using rails new testapplication somewhere to create an empty rails application. Then copy the Gemfile to your actual application. It will get you started by including rails and other common gems.
It is VERY hard to work out exactly what gems are needed. The best you can do is try adding them one by one as you look through the code.
Again, here, MethodNotFound errors are your FRIEND. When you test the application, based on the gems you have added, it might detect some missing methods which might be supplied by gems. Some missing methods on models might indicate missing gems (or they might indicate missing fields/columns in the database). However, missing methods on Controller or ActiveRelation classes are VERY likely because of missing gems.
You will have to look through the code and try to infer what gems to add.
If it uses methods like can, can?, and has a file app/models/ability.rb, then you need gem 'cancan'. If it calls devise in a model, it needs gem 'devise'. Many common gems can be seen at http://ruby-toolbox.com.
After adding gems to your Gemfile, you should run bundle on your command line to install the new gems before testing again. When you test it again, you should restart your test server. Rerun bundle exec rails server to start a local test server on localhost:3000 or something like that.
You can simply copy the Rakefile from rails new testapp, and it will probably include everything you need.
Missing Tests
The missing test/ directory is not relevant to your actual application. It is not required to run the application. However, it does hold automatic scripts to test your application. You will have to re-write new tests if you want to automatically test your application. However for the purpose of getting your application back up, you can ignore it for now.
Missing vendor directory
Some extra code is not installed as a gem, but as a plugin. Anything installed as a plugin is lost if you don't have the vendor directory. As with gems, the best you can do is try to infer what might be missing, and re-download the missing plugin, either re-installing the plugin, or using a gem replacement.
Additional tips:
Try reading some of the comments which might name some of the gems used.
If a method or set of methods are missing, that you think are not database fields/columns, it might be due to a missing gem. The best thing to do is to search google for those method names. Eg. if it is missing "paginate", you can search "rails paginate gem", and see what likely gems you might need. This example will probably come up with "will_paginate", and "kaminari". Then you have to try and infer which of the gems are required. Maybe do a grep will_paginate app -r on the command line to see if it is using will paginate. The grep command searches for the string "will_paginate", in the directory called "app", -r makes it do this recursively for all files
Even though rails is a full stack web framework it would work with out some parts as well, if you wish to,
Ex: in your case
db - directory is there for keep the migrations to create you DB/tables, but if you are using a legacy DB or the database stuff is handled by DB administrators, you might not want it. (you can simply connect to the DB via database.yml file)
Gem file is helping you to keep all the gems (libraries) in one place as you do with Maven (in java)
test, again if you done write test cases (which is absolutely a bad idea), you done need this
vendor, is for 3rd party plugins and doc is for documentation, so same rule applies, if you done need them you can skip them
Hibernate in rails called "Activerecord", same concept, a model is bind with a database table (technically model represents a raw in the table)
So if you really want them add them but if not just leave them
BUT, I think having a proper Gem file and test cases is a must
welcome come to Rails
HTH
In the following, I assume you already know how to:
dump your database schema into an SQL file
start a Rails console (rails c)
generate a Rails migration
Here's what I think you should do.
Identify which of your classes correspond to physical tables (you mention some views in your question, which leads me to believe a subset of your models are bound to database views instead of actual tables). To do this you need to match the definitions of your models (classes which extend ActiveRecord::Base) to CREATE TABLE statements in your schema dump. For instance, class Person in your Ruby code matches to CREATE TABLE people in your DB schema dump.
Once you identified those models (class names), you start up a Rails console and you type those model names, one at a time, and press Enter. The console output for a model called Person would presumably look like this:
>> Person
=> Person(id: integer, first_name: string, last_name: string)
You then take what's inside the parentheses, strip the leading id: integer,, get rid of commas, get rid of those blanks after the colons, thus obtaining something like this:
first_name:string last_name:string
Having done this, the command to generate the migration would look like this:
rails g migration Person first_name:string last_name:string
You then start a new Rails project somewhere else, perform all of these migrations and inspect the contents of db/migrate. Your migrations are most likely 90% done, what you still need to do is replace some instances of t.integer with t.references, and other minor stuff that's completely domain-specific and impossible to capture in a generic answer.
HTH.

Production mode: what is "the best way"\"the most commonly used approach" to change and add data in database?

I am using Ruby on Rails v3.0.9 and I have a web application running in production mode. I would like to change and add some data in the database (also, I would like to make that these data changes take effect in development mode - that is, for example, that the added data should be present also in development mode when I am running and developing my application on my local machine)...
... what is "the best way"\"the most commonly used approach" to do that? I mean, for example, should I create a migration file with in some User.create(:name => '...', :surname => '...', ...) statements and run those or there are other ways to accomplish what I would like to do?
Note: I do not need to populate the database with initial data (I already made that in the seed.rb file). I just need to update and add database table rows.
seed.rb should be use only for initial set of values.
rake task should be use only when you want to update data any existing columns.
migration should be use when you need to change the schema of the table.
You should use the file db/seed.rb to accomplish this task
Here is an example on how to use it: http://asciicasts.com/episodes/179-seed-data

Having trouble getting started with Ruby on Rails

I'm wondering if someone can address some of the issues I am having? I create a rails app:
rails myapp -d mysql
cd myapp
haml --rails .
rake db:create:all
Then I want to use a mysql client to create tables. Lets say users and customers. A customer is also a user so you have schema like this:
users
----------------
id int, not null, primary key, auto increment
first_name varchar(50) not null
last_name varchar(50) not null
email varchar(50) not null unique
password varchar(50) not null
created_at datetime not null
updated_at datetime not null
customers
----------------
id int, not null, primary key, auto increment
user_id int, unique
-- some other stuff that is customer specific
what rails script commands do I need to run to get model, views and controllers created and completely filled out under my rails app? I tried this:
ruby script/generate scaffold user
ruby script/generate scaffold customer
which creates the files but the models are empty:
class User < ActiveRecord::Base
end
whats the deal? Also, I want to create an administration section to manage stuff. I figured out that I need to add routes for those:
map.namespace :admin do |admin|
admin.resources :users
admin.resources :customers
end
what else do I need to get the administration section going?
Also here are the versions of ruby/gems I am running:
ruby 1.8.6
rails 2.3.5 & 2.3.2 <- I'm using 2.3.2 because haml
wasn't working (or some other plugin) with 2.3.5
haml 2.2.15
rspec 1.2.9 <- I saw from another thread that I might need
this when creating an adminstration section (rspec_controller etc)
Models are supposed to be empty by default because database schema is saved into the schema.rb file and managed using migrations.
From your answer I understand you are looking for a prepackage solution to write a couple of configurations and get everything, from controller to administration cooked for you.
I'm sorry, Rails doesn't offer you this feature. If you want an administration section you actually have to code it.
It includes:
creating your views and templates
creating your actions
mapping your routes
writing your tests
The scaffold only provides you a starting point but this is a starting point you should adapt and extend to your needs.
If you want the scaffold to auto-generate your initial views according to your database table, you can pass the arguments to the command line tool
ruby script/generate scaffold user name:string age:integer
But if you want to add a new field later, you'll have to write a new migration and edit your views/actions accordingly.
More information are available in the Rails Guides and Wiki.
Rails is designed for database independence with all the 'creation' done via the migrations located in db/migrate.
To create the appropriate DB tables you then simply run rake db:migrate and any migrations will be executed to create the necessary DB tables.
A good place for more information is the Rails Guides which has an example application to work through.

Ruby on Rails Migration - Create New Database Schema

I have a migration that runs an SQL script to create a new Postgres schema. When creating a new database in Postgres by default it creates a schema called 'public', which is the main schema we use. The migration to create the new database schema seems to be working fine, however the problem occurs after the migration has run, when rails tries to update the 'schema_info' table that it relies on it says that it does not exist, as if it is looking for it in the new database schema and not the default 'public' schema where the table actually is.
Does anybody know how I can tell rails to look at the 'public' schema for this table?
Example of SQL being executed: ~
CREATE SCHEMA new_schema;
COMMENT ON SCHEMA new_schema IS 'this is the new Postgres database schema to sit along side the "public" schema';
-- various tables, triggers and functions created in new_schema
Error being thrown: ~
RuntimeError: ERROR C42P01 Mrelation "schema_info" does not exist
L221 RRangeVarGetRelid: UPDATE schema_info SET version = ??
Thanks for your help
Chris Knight
Well that depends what your migration looks like, what your database.yml looks like and what exactly you are trying to attempt. Anyway more information is needed change the names if you have to and post an example database.yml and the migration. does the migration change the search_path for the adapter for example ?
But know that in general rails and postgresql schemas don't work well together (yet?).
There are a few places which have problems. Try and build and app that uses only one pg database with 2 non-default schemas one for dev and one for test and tell me about it. (from thefollowing I can already tell you that you will get burned)
Maybe it was fixed since the last time I played with it but when I see http://rails.lighthouseapp.com/projects/8994/tickets/390-postgres-adapter-quotes-table-name-breaks-when-non-default-schema-is-used or this http://rails.lighthouseapp.com/projects/8994/tickets/918-postgresql-tables-not-generating-correct-schema-list or this in postgresql_adapter.rb
# Drops a PostgreSQL database
#
# Example:
# drop_database 'matt_development'
def drop_database(name) #:nodoc:
execute "DROP DATABASE IF EXISTS #{name}"
end
(yes this is wrong if you use the same database with different schemas for both dev and test, this would drop both databases each time you run the unit tests !)
I actually started writing patches. the first one was for the indexes methods in the adapter which didn't care about the search_path ending up with duplicated indexes in some conditions, then I started getting hurt by the rest and ended up abandonning the idea of using schemas: I wanted to get my app done and I didn't have the extra time needed to fix the problems I had using schemas.
I'm not sure I understand what you're asking exactly, but, rake will be expecting to update the version of the Rails schema into the schema_info table. Check your database.yml config file, this is where rake will be looking to find the table to update.
Is it a possibility that you are migrating to a new Postgres schema and rake is still pointing to the old one? I'm not sure then that a standard Rails migration is what you need. It might be best to create your own rake task instead.
Edit: If you're referencing two different databases or Postgres schemas, Rails doesn't support this in standard migrations. Rails assumes one database, so migrations from one database to another is usually not possible. When you run "rake db:migrate" it actually looks at the RAILS_ENV environment variable to find the correct entry in database.yml. If rake starts the migration looking at the "development" environment and database config from database.yml, it will expect to update to this environment at the end of the migration.
So, you'll probably need to do this from outside the Rails stack as you can't reference two databases at the same time within Rails. There are attempts at plugins to allow this, but they're majorly hacky and don't work properly.
You can use pg_power. It provides additional DSL for migration to create PostgreSQL schemas and not only.

Resources