I'm working on a Rails app that has one database per account. (I know this is a controversial approach in itself, but I'm confident it's the right one in this case.)
I'd like to automate entirely the process of creating a new user account, which means I need to be able create a new database and populate it with some seed data programatically from within a Rails app.
My question, then, is how best to do this? I don't think I can just run migrations from within the app (or, if I can, how?), and just running the straight SQL queries within the app with hardcoded CREATE TABLE statements seems a really unwieldy way of doing things. What approach should I take, then?
Thanks in advance for your help!
David
This is an approach that my application requires. The app provides a web front-end onto a number of remote embedded devices which in turn monitor sensors. Each embedded device runs a ruby client process which reads a config file to determine its setup. There is a need to be able to add a new sensor type.
The approach I have is that each sensor type has it's own data table, which is written into by every device which has that sensor. So in order to be able to create a new sensor type, I need to be able to set up new tables.
One initial issue is that the remote embedded devices do not have a rails app on them - therefore table name pluralization is a bad plan, as the pluralization rules are not accessible to the remote devices. Therefore I set
ActiveRecord::Base.pluralize_table_names = false
in config/environment.rb
The data on each sensor device type is held in a SensorType model - which has two fields - the sensor name, and the config file contents.
Within the SensorType model class, there are methods for:
Parsing the config file to extract field names and types
Creating a migration to build a new model
Altering a particular field in the DB from a generic string to char(17) as it is a MAC address used for indexing
Altering the new model code to add appropriate belongs_to relationships
Build partial templates for listing the data in the table (a header partial and a line_item partial)
These methods are all bound together by a create_sensor_table method which calls all the above, and performs the appropriate require or load statements to ensure the new model is immediately loaded. This is called from the create method in the SensorTypeController as follows:
# POST /device_types
# POST /device_types.xml
def create
#sensor_type = SensorType.new(params[:sensor_type])
respond_to do |format|
if #sensor_type.save
#sensor_type.create_sensor_tables
flash[:notice] = 'SensorType was successfully created.'
#etc
Related
I have 2 Rails applications. The first one manages user data. The second one has read only access to the first's database to retrieve that user data.
user = FactoryBot.create(:user)
# Test user associations that only exist in the 2nd application
Obviously that line will fail as the user cannot be created due to database-level permissions. My first thought would be to open up the first database's _test database to have full write permissions, but this feels wrong as it would have different permissions than the production environment, potentially hiding/causing other issues.
What is the best approach for using FactoryBot to test aspects of the second application using mock user data from the first?
Update
One thought I had was to pre-load a dummy test database with data and ensure the 2nd application has read only access to it. Then my tests would simply query for an existing user (would need to have prior knowledge about the data inside though) instead of using FactoryBot to create ones. Is this a viable approach?
Loading a fixture would be a good choice here as you can simulate the read only database with your user data interactions.
You will need to read in a yml or xml file similar setup to your db .. parse out the mappings of the file and then you can use it.
Quick example:
def fixture_file_path(filename)
Rails.root.join("spec/fixtures/#{filename}").to_s
end
def read_fixture_file(filename)
File.read fixture_file_path(filename)
end
let(:fixture) { read_fixture_file("file.xml") }
Then create a subject here which will be useful as you will be calling this in many tests .. call the fixture
subject(:service) { described_class.call fixture }
Then you can go from there and build the interactivity to test how you need.
I'm wondering if anyone could shed some light on the best way to test code that works with database models, but does not care what that model is.
Our app has a kind of synchronisation engine that keeps data on a remote server in sync with data on our system, and operates on a number of database models. It is also designed to work with multiple remote systems, and as such contains a number of internal data models which later get mapped to our actual database records.
As an example, we have something like this:
class RemoteResource < Syncable
maps_to ::InternalDbModel
....
end
Here, the sync engine would pull data from any of the remote servers and convert it into a RemoteResource instance, and later this would get translated into an InternalDbModel for persistence.
Due to the generic design, the sync engine doesn't care what database models it is converting to. So long as they meet certain criteria, they are valid.
My question revolves around testing this sort of code. Due to time constraints, I've had to write tests that I simply don't like - the tests involve creating records of actual models used by the app, but I don't like this for a number of reasons:
Each test has to know about the model in order to create the records
If the model has other requirements, they must be fulfilled first, which is completely irrelevant for the test itself
It is not the model that I want to test
It makes the tests brittle to any changes in those models
The syncable class is fine, as I am able to simply stub a class in the test and that works fine. But how can I do something similar for the active record model? Is there a way that I can create a kind of anonymous model class for these kind of tests? I will need to be able to persist the data as some of the sync engine process tests will require that data already exists, but i want this data to be completely independent of the main app itself.
I hope this makes sense
Example
Sync engine resource
class Integration::Resources::Account < Syncable
maps_to ::Account
string :name
string :description
belongs_to :company, Integration::Resources::Company, required: true
belongs_to :currency, Integration::Resources::Currency, required: true
end
Part being tested
I want to test a bit of code that checks that the required belongs_to relations of the Account resource as present. If they're not, it simply ignores the resources, but otherwise it continues.
Part of this involves loading the database records that are associated with the resources. So if the currency association has been set to an instance of the Integration::Resources::Account class, then the engine will retrieve that record from the database. If that record is not found, then the association is considered missing and thus the resource is ignored as it is required.
In this scenario, I currently have to:
Create a currency record
Create a company record
Instantiate a currency resource
Instantiate a company resource
THEN instantiate the account resource with the other resources, and run the test
To me, there is far too much knowledge here about the Account resource, as this is not what I am testing. I simply want to test the code that is ignoring resources with a missing association.
What I want to do is
- Create a dummy model class
- Only a single association
- Create a dummy resource class (this is ok)
- Only a single association
- Test
This way the test only knows what it needs to know. Any changes to any other code would then not break this test which stops it being so brittle.
in the application i am currently creating in ruby on rails. I am trying to do some tests in rails console where i have to destroy data in the database and the database is connected to a server. I am importing an XML and parsing it and putting it into a database with scaffolding.
Now what i need: Basically what i am attempting to do is to destroy the data and replace it with a new one every week..but the problem i am getting, the userid is gone up to 700+ and there are only 50 records :S cause it doesnt reset...
To delete all records i am currently using "whatever.destroy_all" does the trick
Any help?
Btw i am using SQLITE
The ID column created in the table usually is set as unique and to increment by 1 for each new record, which is why each time you destroy and add new data the ID keeps getting higher.
The fact that the ID # is getting larger and larger is not an issue at all.
If you really want to start back at zero, I would think you could drop the table and recreate it, but that seems like overkill for a trivial issue.
Regarding the connection to the other scaffold, how are you connecting the two and what do they both represent?
Ideally the data population for testing should be done through fixtures (or easy tools such as factorygirl etc..)
The main advantage of having a fix data set is you can run your tests in any environment. But as per your requirement you can do something like this,
When you populate the date through the active records pass the id parameter as well
Ex: User.new(:id => 1, :name => "sameera").create
By this way you can have constant id's But make sure you increment the id accordingly.
I have a standard rails application, that uses a mysql database through Active Record, with data loaded through a separate parsing process from a rather large XML file.
This was all well and good, but now I need to load data from an Oracle database, rather than the XML file.
I have no control how the database looks, and only really need a fraction of the data it contains (maybe one or two columns out of a few tables). As such, what I really want to do is make a call to the database, get data back, and put the data in the appropriate locations in my existing, Rails friendly mysql database.
How would I go about doing this? I've heard* you can (on a model by model basis) specifiy different databases for Rails Models to use, but that sounds like they use them in their entirety, (that is, the database is Rails friendly). Can I make direct Oracle calls? Is there a process that makes this easier? Can Active Record itself handle this?
A toy example:
If I need to know color, price, and location for an Object, then normally I would parse a huge XML file to get this information. Now, with oracle, color, price, and location are all in different tables, indexed by some ID (there isn't actually an "Object" table). I want to pull all this information together into my Rails model.
Edit: Sounds like what I'd heard about was ActiveRecord's "establish_connection" method...and it does indeed seem to assume one model is mapped to one table in the target database, which isn't true in my case.
Edit Edit: Ah, looks like I might be wrong there. "establish_connection" might handle my situation just fine (just gotta get ORACLE working in the first place, and I'll know for sure... If anyone can help, the question is here)
You can create a connection to Oracle directly and then have ActiveRecord execute a raw SQL statement to query your tables (plural). Off the top of my head, something like this:
class OracleModel < ActiveRecord::Base
establish_connection(:oracle_development)
def self.get_objects
self.find_by_sql("SELECT...")
end
end
With this model you can do OracleModel.get_objects which will return a set of records whereby the columns specified in the SELECT SQL statement are attributes of each OracleModel. Obviously you can probably come up with a more meaningful model name than I have!
Create an entry named :oracle_development in your config/database.yml file with your Oracle database connection details.
This may not be exactly what you are looking for, but it seems to cover you situation pretty well: http://pullmonkey.com/2008/4/21/ruby-on-rails-multiple-database-connections/
It looks like you can make an arbitrarily-named database configuration in the the database.yml file, and then have certain models connect to it like so:
class SomeModel < ActiveRecord::Base
establish_connection :arbitrary_database
#other stuff for your model
end
So, the solution would be to make ActiveRecord models for just the tables you want data out of from this other database. Then, if you really want to get into some sql, use ActiveRecord::Base.connection.execute(sql). If you need it as a the actual active_record object, do SomeModel.find_by_sql(sql).
Hope this helps!
I don't have points enough to edit your question, but it sounds like what you really need is to have another "connection pool" available to the second DB -- I don't think Oracle itself will be a problem.
Then, you need to use these alternate connections to "simply" execute a custom query within the appropriate controller method.
If you only need to pull data from your Oracle database, and if you have any ability to add objects to a schema that can see the data you require . . . .
I would simplify things by creating a view on the Oracle table that projects the data you require in a nice friendly shape for ActiveRecord.
This would mean maintaining code to two layers of the application, but I think the gain in clarity on the client-side would outweigh the cost.
You could also use the CREATE OR REPLACE VIEW Object AS SELECT tab1., tab2. FROM tab1,tab2 syntax so the view returned every column in each table.
If you need to Insert or Update changes to your Rails model, then you need to read up on the restrictions for doing Updates through a view.
(Also, you may need to search on getting Oracle to work with Rails as you will potentially need to install the Oracle client software and additional Ruby modules).
Are you talking about an one-time data conversion or some permanent data exchange between your application and the Oracle database? I think you shouldn't involve Rails in. You could just make a SQL query to the Oracle database, extract the data, and then just insert it into the MySQL database.
I have just started Rails and have a basic question.
I need to add customer properties(like email id etc) so that the Rails app can read them at runtime. How can I do this ?
Can I add them to development.rb and if so how can I read it ?
In java I would have created a properties file and read it from my app.
thank you,
firemonkey
Are you trying to do store and load configuration settings?
It's easy to store configuration settings in a yaml file and load them with initializers - loads better than littering your environment files.
This Railscast: http://railscasts.com/episodes/85-yaml-configuration-file shows you how.
I'm not sure exactly what you are asking. I'm guessing you want an initial set of data in the database that you can access when you actually run the app? If that is so check out this other SO question How (and whether) to populate rails application with initial data
It's a little unclear exactly what you're trying to do, but it sounds like maybe you have a model called Customer and you would like to add some attributes to it, such as email address, id, and so on?
Basically, with Active Record you don't need to do anything special to add a simple attribute (like a string or an integer). Just add a field called "email_address" to your customers table in the database, and all of your Customer objects will automagically get "email_address" and "email_address=" methods (not to mention the Customer class itself getting "find_by_email_address" and other useful methods as well). If you are adding a field containing another model, it's a bit more complicated - add a "something_id" field to the table, and an association to the class definition (eg, "has_one :something"). For more information, see the ActiveRecord api documentation.
You don't have to use any particular means to add the field to your database, but you might want to consider Migrations. Migrations are a convenient way to keep your schema versioned and synchronized across multiple machines.
If you are building your model right now, there's a short cut built in to the generator to add fields. Instead of just saying...
script/generate scaffold customer
...you can say...
script/generate scaffold customer email:string name:string badge_number:integer
...and it will generate all the appropriate fields in your migration, as well as adding them to your generated views.