Ruby on Rails what is "say" method? - ruby-on-rails

I was taking a look at the template file #excid3 did for his great tool Jumpstart (the public one). Taking a look at the template file, I saw from line 274 on, a bunch of say methods, it looks like the normal puts but if you take a look closer, there is a line that says:
say "Jumpstart app successfully created!", :blue
It gives color to the text! I know that some gems can do that too.
Taking a look at the apidock, it exists as an ActiveRecord::Migration class method but there is no more information about it; just some comment someone did in a deprecated version.
It is strange that it can be used in a template file when it is an ActiveRecord::Migration class method, or not?

This method is an instance method of the class Thor.
You can take a look to a clear example here.
How to use it standalone? With the same example as in the question to log the text with blue color:
Thor.new.say "Jumpstart app successfully created!", :blue

Related

Ruby on Rails extending a gem's class and changing its inheriting class

I have a web app built on Ruby on Rails.
In this app obviously use different Gems.
Iv come to a point where i want to extend some specific gem's classes, and add methods to it.
Now i have a use case where i want to extend a gem's class, but instead of adding methods, i want to change its inherting class
lets take the Impressionist Gem for example:
Iv created a new class in my app - app/models/impression.rb
class Impression < ActiveRecord::Base
establish_connection(ENV[App_LOGS_DB'])
end
i want to change the Inheritance to use a my custom class called LogsBase
class Impression < LogsBase
end
the LogsBase class is definend as follows:
class LogsBase < ActiveRecord::Base
establish_connection ENV['APP_LOGS_DB']
self.abstract_class = true
end
When in try to run the server, the following exception is raised:
/gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb:5:in `<main>': superclass mismatch for class Impression (TypeError)
which from my understanding basically means there is a conflict between the gem's impression class definition and my own extention of that class.
Can anyone please help in finding out a way that i can change the Impression class inherting class, while still perserving the class's behaviour and making my server run properly?
PS: the goal of all this is to write the impressions data into a different database (logs db) rather than the main app db. in order to do that i need to establish a connection to the logs db, but if ill do it within the Impression class directly , it will blow up my pool of DB connections as indicated in the following link:
https://www.thegreatcodeadventure.com/managing-multiple-databases-in-a-single-rails-application/
thats why i need the abstract LogsBase class.
Any help will be appreciated.
Disclaimer: do not do that!
The only way I can think of is a nasty hack, neither reliable, nor robust, that is not compatible with newer versions of your external gem. Since Ruby does not allow to redefine the classes ancestors, you might (but please don’t):
grab the content of original /gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb file.
copy-paste it into your /blah/foo/impression.
make your class be loading impressionist/models/active_record/impression explicitly.
in the very second line of the file unset original class.
Something like this:
require 'impressionist/models/active_record/impression'
Object.send :remove_const, 'Impression'
class Impression < LogsBase
# ORIGINAL CONTENT OF THIS FILE
end
There is no (sensible) way to redefine a base class in ruby. It's possible, but only via weird hacks.
I would suggest taking one of two routes here:
Fork the library, and make the base class configurable (with backwards compatibility).
Don't do this via inheritance. Instead, put establish_connection ENV['SPLACER_LOGS_DB'] into a module, and include it in the class.
I would be inclined to use option 2 for now, as it's a quick/simple workaround that should fit well with the rest of the application.

Double colon in class name and RubyMine complaints about short name

I have the following autogenerated controller in
conrollers/v2/base_controller.rb.
class V2::BaseController < ApplicationController
end
It was generated by Versionist gem. I am trying to make a controller inherited from V2::BaseController. I wrote
class V2::MainController < V2::BaseController
def index
render :text => 'abcde'
end
end
It works fine and I can see my text rendered in browser. However, RubyMine IDE complains that the class name V2 in V2::MainController is too short and I should rename the class.
I am confused because I thought that V2:: means that we define a new class inside V2 module. If I am wrong, then why does RubyMine ignore the same problem with BaseController?
UPD: RubyMine complaint
RubyMine uses reek for code smell detection.
Warning it's giving you is called Uncommunicative Module Name.
Uncommunicative Module Name checks for:
1-character names
any name ending with a number
In your case warning was caused with 2 in V2. Even for Version2 it would be the same.
But it's actually only a recommendation. Ruby works fine with this code.
Nah, it's just a notice for you as a programmer. Short variable names are usually cryptic and less intention-revealing, so it's a nice check to have, but is definitely not a required one.
I think that V2 is perfectly fine for your case, but if you're still concerned, just rename it to Version2 to make Rubymine happy. I don't know if it will be still compatible with the gem you use. it seems Rubymine doesn't like any variable with a number on the end.
But why does IDE show the notice only for MainController?
I can think about 2 options here:
It's some glitch in RubyMine indexing. Or maybe it was made this way not to spam your file tree with red underlines (one is actually enough for you to notice that). Try restarting the IDE and see if it goes away.
RubyMine can't find definition of V2 module, because V2 in class V2::MainController is a reference to defined module somewhere, and not its definition. Solution: create the empty module and see if your warning goes away.
app/controllers/v2.rb
module V2
end

Unable to initialize class in Rails App

Directory:
Prototype
-app
-assets
-controllers
---welcome_controller.rb
domainobjects
---SimilarJob.rb
Utilities
--API.rb
Controller Code
require_relative '../domainobjects/SimilarJob'
class WelcomeController < ApplicationController
def index
foo = API.new('DEVKEY')
res = foo.RetrieveFacts("Test", "Me")
#newResult = SimilarJob.new("test") <-- Failing Line!!!
render :text => res["Response"]["IsInternationalResponse"]
end
end
Object Code
class SimilarJob
end
I stripped out some things, but the API class exists in a separate directory, "Utilities", and for some reason I don't even have to reference it using the "requires_relative" keyword. It's a wrapper class that includes HTTParty and makes a successful GET request to my external API every time. Can someone explain why I seemingly don't have to reference it anywhere?
Alternatively, attempting to initialize the SimilarJob class fails each time. The error is:
uninitialized constant WelcomeController::SimilarJob
From what I researched here and on the web, this means I'm not referencing the file correctly. To test this out, I tried naming it incorrectly in the "requires_relative" statement and the framework informs me that the requested file could not be loaded. So it seems like Rails is finding my class, it just won't initialize it for some reason.
The most maddening part is that I'll make a few small changes to SimilarJob, restart my server, and it'll work all of a sudden. If I stop and start the server again, it's back to the error I pasted below.
This is my first time really digging in something other than .NET MVC or KnockoutJS..would you guys mind pointing out the error of my ways?
EDIT: I used the generate command for this controller, so all views and routes work appropriately. In fact, if I comment out the problematic line, the property I'm referencing on the last line in my JSON response renders to the file just fine.
EDIT v2: Strangely enough..changing my class name to Jobs (one word) is getting rid of this error. This comes off as bizarre! Can anyone confirm that this is my issue?
Names matter, and you've named your file wrong. SimilarJob.rb needs to be similar_job.rb.
Similarly, your API file should be called api.rb, and the class it defines should be called Api. This stuff is important, as you've deviated badly from Rails convention, and are suffering for it.

Expected file to define module, but it is defined... why does ruby disagree?

The first line of text is the LoadError
the second line of text in the image is the folder where the file, shared.rb resides in my rails project.
And the sytax colored stuff is the top part of shared.rb
as you can see, shared.rb defines NamedScope::Shared, so why is RoR saying that it isn't?
using rails 2.3.8
UPDATE:
tried this:
module NamedScope
module Shared
in the same file, shared.rb in {AppRoot}/lib/named_scope/
which also didn't work (same error)
UPDATE 2: This error was caused my a model class not having a Constant defined.
I just had
CONSTANT_NAME
instead of
CONSTANT_NAME = value
this is upsetting, as I feel lied to o.o
Did you define the NamedScope module before? You might need to do:
module NamedScope
module Shared
# do your thing here
end
end
I would need to see more of the code to follow.
I've had that issue when the code uses a Class that is defined somewhere else and the magic name resolution is not strong enough. Like if I have a XyzLoan class that extends the Loan class but I did not require it or use it before. It shouldn't fail but it does.
If that is the case you can do a binary search for the problem by removing halves of the code and try again until you find what is causing it.

How do I add a method to a ruby gem without editing the gem source?

I am using the acts_as_taggable_on gem and would like to add a method to one of the gem source files (tag.rb), but I do not want to change the gem source in any way.
I have tried creating my own tag.rb file to in the /app/models directory or in the /lib directory, and then adding the desired method to that file expecting that ruby will merge the two tag.rb files
But when I do I get a NoMethodError: undefined method ...
What am I missing?
I think you're right that reopening the Tag class is the way to go. I wouldn't introduce another level of inheritance unless it really made sense for your code.
I'm not sure, off the top of my head, why reopening the Tag class didn't work. A few thoughts:
1 - When you wrote your own Tag class, did it descend from ActiveRecord::Base? The Tag class in acts as taggable on does, and I could see how neglecting that might mess things up.
2 - If I needed a place to put code that reopened a plugin class for a single method, I'd probably put it in an initializer file (such as config/initializers/tag_patch.rb). Just to keep things clean.
3 - If all else fails and you still can't get the Tag class reopened properly (for whatever reason) there are other metaprogramming techniques you might try to add the method. For example:
Tag.send(:define_method, “method_name”) do
#code for your method
end
Wait, you shouldn't be adding method to the file, but to the class instead. Are you familiar with the concept of reopening the class? You can't add a method just by naming your file same as the one which original class is defined in. Fortunately. :)

Resources