0

I want to develop a rubygem which is intended to be installed in a rails application.

The gem will contain few models and their database migrations.

Also I would like to add tests asserting the models and their relationships. I prefer RSpec for doing that.

While I was about to start I got stuck with a question that how to use ActivRecord in a gem so that using the tests I can insert the fixture data and test the relationships and behaviour.I believe SQLite should prove to be the best option for database here.

Note: I haven't developed any Rubygem before and this will be the first one I am attempting. Thus any help will be highly appreciated to guide me in the right direction.

Thanks.

Update on Jul 30, 2018

I found a similar question Ruby Gem Development - How to use ActiveRecord? which is exactly what I want to do. But the answers are not quite clear. Hope this helps in understanding my question.

Jignesh Gohel
  • 6,236
  • 6
  • 53
  • 89
  • What is the question? – jvillian Jul 27 '18 at 17:03
  • Want to develop a rubygem wherein I will have some ActiveRecord-based models which will be directly used by a Rails application. I also want to test the models in my gem using rspec. I don't know how to approach this. – Jignesh Gohel Jul 30 '18 at 09:49

1 Answers1

1

You can get the functionality you are looking for using generators. Basically you write templates for the files that the user should have (models, migrations, tests) and save them with your gemfile. You then allow the user to copy those files in using commands.

This is a good link that goes into much more detail on generators, but here is a small example that I used in one of my gems:

gem_name/lib/generators/gem_name/install_generator.rb

module GemName
  class InstallGenerator < Rails::Generators::Base
    include Rails::Generators::Migration

    # Allow user to specify a different model name
    argument :user_class, type: :string, default: "User"

    # Templates to copy
    source_root File.expand_path('../../../templates', __FILE__)

    # Copy initializer into user app
    def copy_initializer
      copy_file('create_initializer.rb', 'config/initializers/gem_name.rb')
    end

    # Copy user information (model & Migrations) into user app
    def create_user_model
      fname = "app/models/#{user_class.underscore}.rb"
      unless File.exist?(File.join(destination_root, fname))
        template("user_model.rb", fname)
      else
        say_status('skipped', "Model #{user_class.underscore} already exists")
      end
    end

    # Copy migrations
    def copy_migrations
      if self.class.migration_exists?('db/migrate', "create_gem_name_#{user_class.underscore}")
        say_status('skipped', "Migration create_gem_name_#{user_class.underscore} already exists")
      else
        migration_template('create_gem_name_users.rb.erb', "db/migrate/create_gem_name_#{user_class.pluralize.underscore}.rb")
      end
    end

    private

    # Use to assign migration time otherwise generator will error
    def self.next_migration_number(dir)
      Time.now.utc.strftime("%Y%m%d%H%M%S")
    end
  end
end

Finally, just some advice/personal opinion; your gem should either run under a variety of test suites and databases or else you should indicate that you only support that setup and assume they are available in the user's project. Though I think you could shoehorn in a second test suite, trying to force a second database wouldn't be possible, also you don't need to worry about the DB using migrations unless you want to use a data type that isn't available in all the supported DBs.

A better approach, in my opinion, would be to write separate generators for the specs you want and let the user run them optionally. This will copy the tests in and allow them to modify if they like.

  • Thanks. That is definitely helpful. However I would want to add handful of ActiveRecord-inherited models in my gem itself and then want to add tests for those models, their relations, behaviours etc in my gem-code itself. I don't want the gem installers to copy those models and instead include it in their Rails application's existing model and start using the behaviour my gem would provide. The requirement can be compared to extracting some working models from my Rails application and make them more generic and reusable and package them into gem. – Jignesh Gohel Jul 31 '18 at 14:41
  • This isn't different than the above. You can have all those things, but you have to give the user a migration to integrate it into their project. Here is the project that I copied the generators from. You can see that it both has RSpec tests and AR inherited models. https://github.com/nicholasshirley/knock_once – oneWorkingHeadphone Jul 31 '18 at 15:49
  • Thanks. The reference you have provided looks relevant. I will go through in detail and start working towards my goal. – Jignesh Gohel Jul 31 '18 at 17:08