I have a problem where I have 2 associated models which are stored in separate databases on the same server.
Say I have two models, City and SportsTeam. I want to be able to find all the sports teams which are nfl teams, and then get their associated cities. I have run into a lot of trouble trying to do this since they are located on separate dbs.
class City
eastablish_connection :city_db
has_one :sports_team
end
class SportsTeam
belongs_to :city
validates :is_nfl_team, :is_mlb_team, :is_nhl_team, presence: true
end
In Rails 5 it's possible, but I would recommend upgrading your app to Rails 6 since you are using multiple databases and Rails 6 support this feature natively.
In Rails 5
You can define another database configuration file, for example, second_database.yml inside the config folder and then load it in an initializer like this: SECOND_DATABASE = YAML::load(ERB.new(File.read(Rails.root.join('config','second_database.yml'))).result)[Rails.env]
Then inside of the models (which its records are in the second database) include this: establish_connection SECOND_DATABASE
Keep in mind that I've worked with multiple databases in Rails 5 and you may run into problems, but what you are trying to do is entirely doable.
In Rails 6
A much better option is to upgrade to Rails 6 and use its multiple database feature, basically what you have to do is:
Define both databases connection inside database.yml.
Add connect_to(:database_one), connect_to(:database_two), etc. at the models depending where their data are.
More details at: https://guides.rubyonrails.org/active_record_multiple_databases.html
Related
I have a separate server that contains a Ruby on Rails API ( DB is postgres) that will used by multiple, different, applications. I was thinking of using schemas to sort the tables that each application will require and have a "common" schema that contains the tables that the applications will share ( Users, Employees, etc). Each application schema would have roughly 10 tables and the common schema would contain about 15. The current plan is to have about 3-5 apps using this API all using the same common tables.
My question is, is it worth implementing Postgres schemas with Ruby on Rails? I've been looking for some resources on the topic, but there doesn't seem to be much information on it. There are a couple articles written in 2011/2012 but nothing closer to 2018. One of the main things I've been looking for is how to create rails migrations with postgres schemas properly.
I also read a comment from a user stating that they have used postgres and rails separately, but would never use them in conjunction.
It feels like a good idea to use schemas to organize the DB but don't want to go down that road if it will require a lot of manual DB work/maintenance.
Thanks,
This can be easily implemented with Rails, you will have to override the default table name expected by Rails to point to a specific Schema though:
class YourSchemaRecord < ApplicationRecord
self.table_name_prefix = 'name_of_your_schema.'
end
class SomeRecord < ApplicationRecord
end
class YourCommonSchemaRecord < ApplicationRecord
self.table_name_prefix = 'public.'
end
class SomeCommonRecord < YourCommonSchemaRecord
end
About Rails migrations, you can either use plain SQL (my favorite option) or use Rails' built-in method but give the "full path" of the table you want to update the structure:
add_column 'name_of_your_schema.some_records', :some_column, :string
I've been reading about Rails Migrations to help me start building a rails project.
I'm a bit confused on the generation of the files in db/migrate.
The way I've been designing my application is by starting with the models... outlining all of the objects that I'm going to have in the system as best I can. I would like to generate the migration files FROM these models automatically with the rails migration generator.
Yes, I know "creating migrations manually is easy." And I know I could do it manually, but what I don't understand is why the tool is separated from the pre-created models.
Based on my understanding from the article and other migration questions on SO, I can generate a migration like so:
rails generate migration SomeObj field:string some_other_field:integer
What I don't get is why I need to pass in the fields when my model already exists for SomeObj? Couldn't Rails detect it from the some_obj.rb and create the migration from there?
Also, when I have a more complex model, with has_many, belongs_to, and has_to_and_belongs_to_many relationships, it would be really nice if it autocreated the JOIN tables and fields with the correct names (e.g. foreign_obj_id, foreign_obj_ids)
In a previous project I didn't have to deal with migrations because I used Mongo+Mongoid - and collections were automatically generated due to the nature of how Mongo works (collections that doesn't exist get automatically created upon inserting or updating). Now with this Rails app I'm using Postgres (but I'm sure the same thing would happen with MySQL or any other relational database).
Anyway, is there no helper for this kind of thing? Do I have to create all these migrations manually?
You've got this backwards. You need to build your migrations first, and your models second. Migrations advance the state of the database. Your models reflect the current state of the database. There is not a 1-to-1 mapping of models to migrations.
I would like to generate the migration files FROM these models automatically with the rails migration generator.
Can't be done.
You use rails generate migration to generate the migration, which, almost as a side-effect, generates a stub model file. You cannot use your existing model file to generate the model's migration, because the model doesn't contain any information about the actual columns that make up the model. Rails would have to extract and imply all the necessary information from your associations/validations, and even then it would get most of the columns wrong.
Also, when I have a more complex model,... it would be really nice if it autocreated the JOIN tables and fields with the correct names
Again, you can't. You're responsible for defining your database schema, and the way you do so is by building migrations. You can do so manually, or via rails generate, but the process you should be following is building your migrations first, and your models second.
By way of example, here is a complete model, ready for production:
class MyModel < ActiveRecord::Base
end
That model definition might wrap a table that contains 10 columns or 1000 columns; you (and Rails) have absolutely no way of knowing based on the model definition.
Here's another model, which contains at least one column, but again, you have no way of knowing what kind of column:
class MyModel < ActiveRecord::Base
validates :code, presence: true, uniqueness: true
end
Is code a string or a number? Should there be an index on the column? There is absolutely no way of knowing.
I have a database with several tables, each one containing columns that may not follow the rails naming convention.
Is there a tool existing to create the ActiveRecord models from those tables or do I need to do this at hand, one by one ?
If I create the ActiveRecord model for one table by hand, would this be ok though ? (no hidden DB identifier needed on top of it ?)
UPDATE
I have tried magicmodels but cannot have it working (it has been a while since it was last modified) and does not seem to be compatible with rails 3.2
What I tried then:
- change the database.yml so it points towards my existing Postresql database
- manually create my models such as:
# app/models/user.rb
class User < ActiveRecord::Base
end
- run the console and tried
User.all
=> I end up with an error saying that contant User was not initialized.
Doesn't the console import the model automatically ? Or is that linked to the fact the configuration I did is not correct ?
http://magicmodels.rubyforge.org/magic_model_generator/ may be what you're looking for. I haven't heard of many tools that give this functionality, though, as many rails apps are designed from scratch instead of given a legacy db and then creating the models from that.
You can easily create models by hand and map them to pretty much any db table. Models have a "set_table_name 'name'" that lets you over-write the rails default convention of a single model mapping to a plural db table name.
ActiveRecord works OK with legacy databases. I did a back-end system that didn't use Rails with ActiveRecord as my ORM. "ActiveRecord Without Rails" got me started. "Using ActiveRecord outside Rails" is also useful. Search Google for "use activerecord without rails" and you'll find even more.
You don't need a fully fleshed out model. Just use a base class for the tables you want and ActiveRecord will query the database for what it needs. It won't know about table relationships, but for general queries it'll do fine. Build the relationships as you go and need them.
I'm designing a ruby on rails app for a pharmacy, and one of the features is that there are stores who have pharmacists who work there. In addition, there are pharmacists, who can work at many stores. This sounds like a job for HABTM, right? Well, being the novice I am, I manually designed a workaround (because I never heard of HABTM - I basically taught myself rails and never got to some of the more advanced relationships). Right now, when a pharmacist is saved, there's a couple of lines in the create and update action of the pharmacists controller that turns the stores that they work at into a string, with each store_id separated by a comma. Then, when a store is displayed, it does a MYSQL request by
#pharmacists = Pharmacist.find :all, :conditions => "stores REGEXP '#{#store.id}'"
Would moving this system over to a rails based HABTM system be more efficient? Of course it would require less code in the end, but would it be worth it? In other words, what benefits, other than less code, would I get from moving this association to be managed by rails?
The benefit is that you will be using the right tool for the job! The whole point of using a framework such as Rails is that it helps you solve common problems without having to re-invent the wheel, which is what you've done here. By using associations you'll also be using a relational database properly and can take advantage of benefits like foreign key indexing, which will be faster than string manipulation.
You should use a has_and_belongs_to_many relationship unless you need to store extra attributes on the join model (for example the date a pharmacist started working at a store) in which case use has_many :through.
Using Rails associations will give you all the convenient methods that Rails provides, such as these:
# Find the stores the first pharmacist works at
#stores = Pharmacist.first.stores
# Find the pharmacists who work at a store
#pharmacists = Store.find_by_name('A Store').pharmacists
A Guide to ActiveRecord Associations
What is the best way to test a model that is using a different database connection in Rails. For example I have a model FooBar that is read only:
class FooBar < ActiveRecord::Base
establish_connection configurations['foo_bars']
# ...
end
Are there any good conventions, hacks, or plugins out there?
In my experience, once the connection is established you can treat the model just like any other model. Since you are just consuming the data that will simplify some of the testing as you wont need to test for data validations.
Obviously because Rails is talking to two different databases from two different models, you won't be able to do joins between the databases and so there will be nothing to test there either.
So, to answer the question: what is the best way to test a model that is using a second database? I would say, exactly the same way that you would test it if it was your only database.
I find that in my models that wrap my legacy databases I have to add some special tie in code that makes things a little more "Rails-y" and makes the view and controller code look like there are has_one and belongs_to type code in there. I do have tests that exercise those custom methods.
Hope that helps.