Rails overload gem models - ruby-on-rails

I'm loading models through a gem, and I want to overload those models. I'm in Rails 3.
What is the best way to do this?
-= More Info =-
Ultimately, I want to run thinking_sphinx against a model in the gem so:
class User < ActiveRecord::Base
define_index do
indexes some_index
end
end
This takes over the gem's model. If I place it into the initializers, it works once then it won't continue to work on any rails server, WEbrick, unicorn, but it works fine in the console.
Thanks in advanced,
Justin

This was my answer.
How to monkey-patch code that gets auto-loaded in Rails?

Related

Rails 6 app not validating belongs_to associations

I have a rails engine which encapsulates a piece of my application's funtionality. I have a bunch of models in the engine, which have various belongs_to associations defined. As of rails 5 these associations are supposed to be required by default, unless optional: true is specified in the definition.
I’m still able to create instances of the models without any validation errors. I haven’t specified optional: true on any of the associations, nor is the config optionconfig.active_record.belongs_to_required_by_default set anywhere. Besides, it was removed in rails 6 anyway.
I can't think of any reason the model instances would not fail validation. I would expect any instances of any model with an undefined belongs_to association would be invalid and raise an error. Why would these records pass validation?
I found my problem, thanks to #MatthiasWinkelmann for the tip. It turns out my engine was not calling load_defaults at all. I needed to add the following to spec/dummy/config/application.rb:
module Dummy
class Application < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
... etc ....
end
end
here is an article containing more explanation:
An upgraded Rails gem does not upgrade your Rails configuration
I probably would have done better to mention in my question that I'm in the process of upgrading my application from Rails 4.2 to 6.1. The change was introduced in Rails 5.

Alternative to the globalize gem

I tried out the globalize gem but this seems like a big overhead. Most of the time I just need one attribute translated. I'm using postgreSQL and would rather use a hstore for this. That way I won't get additional tables and performance should be at least as good if not better.
Are there any gems that use this approach or would this mean a custom development?
Seems like you're searching for the hstore_translate gem. I have not tested it but it appears to suit your needs precisely from the description:
Rails I18n library for ActiveRecord model/data translation using PostgreSQL's hstore datatype. It provides an interface inspired by Globalize3 but removes the need to maintain separate translation tables.
I've been using the hstore_translate gem and love it.
Say for example you have a Project model schema with title:string and content:text. If you want content to be translated, all that needs to be done is to create a migration:
class AddTranslationToProjects < ActiveRecord::Migration
def change
add_column :projects, :title_translations, 'hstore'
end
end
and inside of project.rb:
class Project < ActiveRecord::Base
translates :title
end
thats it! Nothing else to do in the form or wherever. Works for integers and booleans as well. The only extra step to do is activate hstore if using postgres: CREATE EXTENSION hstore
I've recently created the gem awesome_hstore_translate, which is based on the original hstore_translate by Rob Worley.
hstore_translate uses alias_method_chain, which got deprecated with Rails 5.0.
My gem has the same functionality as it's original, but it's a bit more modern. It stores it's data in columns without a suffix, because I think the database model looks more clean that way. The raw data is still available. E. g. Page.first.title_raw will give you the hstore hash.

Using a database within a Ruby gem

I'd like to use a database within a Ruby gem that I'm writing. The gem is meant to be used within Rails applications, and will contain an inverted index of documents passed in from the main Rails app.
I'm a bit confused as to how to go about this. Should I hook into the main Rails database somehow? Or should I have a standalone database? Ideally I'd just like to use ActiveRecord to create, update, delete and query entries but I am not sure how I'd set this up.
Data would go into the database at this point:
module ActiveRecordExtension
extend ActiveSupport::Concern
class_methods do
def foo
"bar"
end
end
included do
after_save :add_to_inverted_index
end
def add_to_inverted_index
# This is where I'd take the fields from the Rails app
# and include them to my inverted index. However, I'm struggling
# to find a way to hook into a database from my gem to do this.
end
end
# Include the extension
ActiveRecord::Base.send(:include, ActiveRecordExtension)
Suggestions are much appreciated! Thanks
Well after your clarification, you should use main Rails database. Just create a migration and insert the table(s) you need. You should do that because:
Everyone that uses your gem will know what is stored at the database.
With migrations, you can easily rollback the migration, making it simple to reverse something, if needed.
There's no need to create extra dependencies. Imagine a project that you did in RoR and think if the mess it would be if every gem that you used created its own database.
Maybe you should take a look at known gems and how they do that. I'm thinking about Devise.

Ruby On Rails - Access model from a different file

I have a model in my rails application which is
class Person < ActiveRecord::Base
..
end
I would like to access this model from a different ruby file for certain manipulations. This is to populate my db. Can somebody please tell me how to go about it?
I am new to ruby on rails and hence a trivial question. I tried including the model by using require or require relative but I get a LoadError
If you use a rake task to populate/manipulate your database then you can solve this problem by making the task depend on the rails environment, this will set up everything you need to access the db:
task :my_task => :environment do
#do whatever with your models here
end

How to get generators call other generators in rails 3

I am experimenting with gem development, right now specifically generators. So far I have successfully created two generators that do their job just perfectly. These two generators are in the same directory.
However, right now I have to call each of them separately.
What I'd like to do is just call one generator and have that generator call all the other ones. Just would type
rails g generator_name
and this would call x other generators.
Does anyone know how would I got about doing this?
Help is much appreciated, thanks!
In your generator, you can just call
generate "some:generator" # can be anything listed by 'rails g'
for example:
module MyGem
class InstallGenerator < Rails::Generators::Base
def run_other_generators
generate "jquery:install" # or whatever you want here
end
end
end
By the way, if you are working on Rails 3 gems, this question can also help out:
Rails 3 generators in gem
Another possibility is to use something like
invoke 'active_record:model', 'foo bar:string baz:float'
which is not as clean as generate, but has one advantage: When your generator gets called via rails destroy, this call -- like may other of Thors actions -- will try to revoke the action of the generator you invoke.
There's a catch however: Probably due to Thors dependency management, this only works once per generator you want to call, meaning that a second invoke of the same generator will do nothing. This can be circumvented by using a statement like
Rails::Generators.invoke 'active_record:model', '...', behavior: behavior
instead. In this case you have to explicitly pass through the behavior of your generator (which is a method returning values like :invoke, :revoke and possibly others, depending on which command -- rails generate, rails destroy, rails update, etc. -- called your generator) to achieve the same result as above. If you don't do this, the generator you call with Rails::Generators.invoke will also be executed when running your generator with rails destroy.
Alternatively you could stick to invoke and try to tamper with Thors invocation system. See also here for example.
Generators are based off of Thor, so you can use the apply method.
This is what the Rails Templater gem does. (Here's a walk through the Rails Templater gem.)
Take a look at the scaffold generator that comes with rails.
/Users/XYZ/sources/rails/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
def manifest
record do |m|
#....rest of the source is removed for brevity....
m.dependency 'model', [name] + #args, :collision => :skip
end
end
Here the scaffold generator is using the model generator. So take a look at the dependency method. You can find the API docs for it over here.

Resources