Extend Rails within Engine - ruby-on-rails

I did a Rails extension as suggested by
extending rails question using Harish Shetty answer.
I like it so much I decided to use it in my Rails Engine. Didn't quite work.
To make it work i place the file active_record_extensions in the Lib/[ENGINE] directory and added the Require active_record_extension to my engine.rb file.
This works, but I wonder if there's is a more proper way to do it.
Also. I ran into an Issue, (don't know if i'm allowed to piggyback a second question).
I have a Model called Translation. When i use the extended class method with that model i invoke an error 'Circular dependency detected' with
raise "Circular dependency detected while autoloading constant #{qualified_name}"
I'm guessing that using the model extension exposed the name to something that doesn't like the fact that I used Translation. (doesn't happen with the other models I have). I get around it by not using the extend class method with that model.

Related

Add a basic UI layer to existing ruby app

First, I am fairly new to Ruby/RoR and so you'll have to forgive me for any wrong terminology, but hopefully I'll get my point across.
I built an ruby app that I am needing to add an extremely simple UI layer using rails. Read up on a previous post of mine that explains the project thoroughly to give you good an idea of what it does. Specifically take a look at the tree outline that I pasted in so you see the existing file structure for the project.
What I need to know, is how to convert this existing project into a rails app? My experience in building something with rails has always started out with rails new app_name, but never anything like this. Any tips would be appreciated.
I saw your parser script, and it is not a daemon (a program that keeps running indefinitely in the background), right?
If I'm right, then you have several options:
The easiest option
Just build a rails application using rails new app_name, and inside some controller action, make a system call to run your script
class SomeController
def some_action
succeeded = system(:ruby, '/path/to/main.rb', '/path/to/some.txt')
# Do some rendering stuff here based on the result of the system call
end
end
This approach is somehow nasty for me, and it's not performant because each system call reads your ruby script and compiles or interprets it then runs it.
The harder option
Refactor your script so that it's features can be wrapped into a gem.
Then you install that gem, require it in your rails app, and use it.
I saw your original ruby script is almost there, it shouldn't be that hard to make it become a gem.
Rails is just "something" on top of Ruby. Especially, you can use any plain ruby objects inside of Rails, anywhere, and this is nothing unusual (google "PORO").
In your case, I would make a simple Rails app in the way you have mentioned yourself with rails new. Then trivially refactor your existing code until you have a simple, standalone class that does what you need to be done but takes its input/output from simple ruby data structures (i.e., method arguments, return values, no global state, no file operations). Then you can use that class from inside your Rails controller (taking input from a HTML form, rendering output to HTML), and also from inside your script (reading input from a file or STDIN, rendering output to STDOUT).
Where you put that class is up to you. In the MVC paradigm, it is not "C" or "V", and one could argue about whether it's "M". So put it into app/models/ or lib/, whatever you like more.
These were great answers and I'm sure they would have worked perfectly. However, they were a little bit more complex than what I was looking for.
What I ultimately ended up doing was just cd into the directory above where the ruby app was located and then just simply ran rails new app_name. Rails will ask if you'd like to overwrite any files that exist already. From there I just integrated my script into the controller actions and created the views.

How can I rename a Ruby library module's namespace?

I'd like to use the ruby Stripe library in a Rails app. It uses the module Stripe as its namespace.
I want to use Stripe as the namespace for my ActiveRecord models, and rename the library module to something like StripeApi, so that e.g. StripeApi::Charge refers to the Stripe library, but Stripe::Charge refers to my Stripe-namespaced ActiveRecord model (so that e.g. Stripe::Charge.create(...) creates a database record, rather than just making API calls).
Is there a good way to do this?
(Sure, I could rename my namespace, or try to use differently named models, but I find that kinda ugly.)
There is no such thing as "namespace" in Ruby. It's just a variable (well, constant):
StripeApi = Stripe
Boom. You're done.
Make sure to set Stripe to a new module, so that you don't accidentally reopen the module when you think you are creating a new one:
Stripe = Module.new
Now you can do
class Stripe::Charge; end
I really recommend to rename your own namespace since you have full control over the code.
Otherwise it could really become a pain in the ass if you want to update the version of the Stripe gem or search for a Bug relating to your namespace as well to the original Stripe namespace.
It's a lot easier to change the own namespace instead of changing an existing gem (eventually for every version again).

Understanding the rails relationship between "require" and class naming conventions

As far as I understand, in Rails you don't have to require most of the files that you use, and that most of these files are auto-magically required or included in your code as you reference appropriate classes.
If I understand If I do the following in some arbitrary file, or via running a script with rails runner myscript.rb
myscript.rb
User.delete_all
#set up a default user
User.create(name: "default", password: "default")
This file automatically sees a class it doesnt recognize, User, and understands via its naming convention that the class must be defined in /app/models/user.rb then this code is somehow made available via require or something similar.
My question is: How does rails implement this feature? This is something I'd very much like to understand.
The answer depends a lot on the environment. In production, everything is loaded at boot time and all the classes are cached. In development, the classes are found with const_missing and reloaded when they change. Take a look here at the Rails initialization process.
Check method autoload, whose planned deprecation has been halted for now, and also const_missing, to name just two. Another available mechanism would be eg. to rescue NameError exceptions for uninitialized constants...

When to consider creating your own Ruby module in a Rails app?

With a Ruby module, you can cluster together a bunch of methods that you might use in one place and then include them into a class so it's as if you had written them in that class.
What kinds of practical uses are there for Ruby modules in a rails app?
I would appreciate if someone could mention an example of where they've actually used a module of their own so I have a sense of what situations I should be thinking about creating them. Thanks.
1) Any time I'm about to duplicate (or substantially duplicate) a piece of code: "oh, i could just cut/paste into this other controller . . . "
2) Any time I write code that is very obviously going to be reused in the future.
3) Code of substantial size that has a specific purpose, where that purpose is fairly distinct from the main purpose of the controller/model. This is somewhat related to (2), but sometimes code won't get reused but a module helps for organization.
You can place them in the /lib directory and they'll be loaded with your Rails project.
For example, you can view this repo of mine of an old project: lib directory of a Rails project
So for example, I have the following module:
google_charts.rb
Module GCharts
class GoogleCharts
def some_method
end
end
end
And anywhere in my Rails app, I can access the methods.
So if I were to access it from a controller, I would simply do:
require 'google_charts'
GCharts::GoogleCharts.some_method
We use modules for functionality that isn't tied to ActiveRecord models and hasn't been abstracted into a plugin or gem.
A recent example from our production code base is a library for integrating with Campaign Monitor for email list management. The core of the system uses our user model, but the actual interaction with the extenrl service is abstracted through a module that lives in /lib.

How are require, require_dependency and constants reloading related in Rails?

How are require and require_dependency different?
How can require_dependency automatically reload classes in development but require can't ?
I digged into Rails' ActiveSupport::Dependencies and dispatcher.rb code. What I saw in require_dependency's code is it basically adds the constants to an autoloaded_constants array. But it gets cleared in clear_application inside dispatcher after each request.
Can someone give a clear explanation or point me to some resources which will help?
require (and its cousin load) are core Ruby methods. require_dependency is a method that helps Rails handle the problem of dependency management. Long story short, it allows Rails to reload classes in development mode so that you don't have to restart the server each time you make a code change. The Rails framework will require_dependency your code so that it can track and reload it when changes are made. The standard Ruby require doesn't do that. As an app (or plugin/engine) developer you should not have to worry about require_dependency as this is purely internal to Rails.
The magic of the Rails class loading process is in the ActiveSupport::Dependencies module. This code extends the default Ruby behavior to allow code inside your Rails app to automatically load modules (including classes which inherit from Module) using Rails' path and file naming conventions. This eliminates the need for the programmer to litter their code with require calls like you would in a plain Ruby application.
To put it another way, this lets you define class Admin::User inside the file app/models/admin/user.rb and have Rails know what you are talking about when you call Admin::User.new from another part of the application like a controller. Without ActiveSupport::Dependencies involved you would have to manually require everything you needed.
If you are coming from a statically typed language like C#, Java, etc then this might be a surprise: Rails code is not loaded until it is needed. For example, a User model class isn't defined and user.rb isn't loaded until AFTER you try to call User.whatever_method_here. Rails prevents Ruby from complaining about that missing constant, loads code for User, and then allows Ruby to continue as normal.
While I can't speak for your specific need, I would be very surprised if you actually needed to use the require_dependency method from within a plugin or engine. If you follow Rails conventions you shouldn't have to tweak the $LOAD_PATH by hand, either. This is not "the Rails way".
In the world of Ruby and also Rails simplicity and clarity is key. If all you want to do is write a plugin or engine and you are already diving deep into internals then you may consider approaching your problem from a different angle. My gut tells me that you may be trying to do something that is needlessly complicated. But then again, I have no clue what you are doing exactly!! :)
require_dependency is useful in an engine when you want to re-open a class which is not defined in your engine (for example in another engine or Rails app) and have it reloaded. In which case something like this works:
# app/controllers/my_engine/documents_controller.rb
require_dependency MyEngine::Engine.root.join('app', 'controllers', 'my_engine', 'documents_controller').to_s
module MyEngine
class DocumentsController
def show
render :text => 'different'
end
end
end

Resources