Method visible everywhere in Rails - ruby-on-rails

How can I make this method, which outputs a yellow line in the log file, accessible from everywhere (Models, Controllers, Views) in my Rails app?
def my_log(text, file = "", line = "")
text.to_s.chomp.gsub!(/%/, "%%")
Rails.logger.debug(sprintf("\033[32m#{file}#{line}\033[0m\033[1m\033[33m#{text}\033[0m"))
end

You could define it in Kernel (NOT recommended):
module Kernel
def my_log(..)
..
end
end
... if you really want it available anywhere.
Or, place something like this in lib/util.rb:
module Util
def self.my_log(..)
..
end
end
... and make sure to require 'util' in your config/application.rb and then you can call this anywhere:
Util.my_log(..)

why not create an initializer and write this method to the rails module?
# config/initializers.rb
module Rails
def self.log_with_colour(message, level = :debug)
text.to_s.chomp.gsub!(/%/, "%%")
logger.send(level, sprintf("\033[32m#{__FILE__}#{__LINE__}\033[0m\033[1m\033[33m#{message}\033[0m"))
end
end
in your code you can then call Rails.log_with_colour("hello") or Rails.log_with_colour("Hello again", :info)

I put stuff like this in config/initializers/app_methods.rb. They don't need to be scoped inside a class or module. Feels a bit hacky but i never had any problems.

Add it as an instance and class method in Object
class Object
def self.my_log(...)
...
end
def my_log(...)
Object.my_log(...)
end
end

Related

Global dynamic path variable

I have several functions in my model
#app/model/game.rb
...
def uncompress_game_files_to_s3
UncompressToS3Job.perform_now(self.files, "assets/#{self.id}/game") if self.files
end
def delete_game_files_from_s3
DeleteFromS3Job.perform_now("assets/#{self.id}/game")
end
def update_game_index_file_url
files = FindFilesOnS3Job.perform_now("index.html", "assets/#{self.id}/game")
self.update_attributes(url: files.first)
end
In all these functions, I use "assets/#{self.id}/game" for S3 key attribute. I would like to use this expression as global variable aws_game_path.
I tried to initialize it in initializer file.
#config/initializers/aws.rb
aws_game_path = "assets/#{self.id}/game"
but since it is out of the model scope, it raises an error undefined method `id'. How can I declare such variable?
I think ActiveSupport::Concern Would be best practice in this case.
Follow the below step to make available to all the model
1: Create a rb lets say active_record_global_var.rb extension file in lib as lib file load first.
2: paste the following piece of code.
module ActiveRecordExtension
extend ActiveSupport::Concern
def set_global_valiable
set_global_id = self
end
module ClassMethods
end
end
ActiveRecord::Base.send(:include, ActiveRecordExtension)
3: Create a file in config/initializers/ directory. Let say extensions.rb and put this code snipped into this file.
4: require "active_record_global_var"
5: Now call set_global_variable instances method on model object. This method would be available for all model.
For example:
User.last.set_global_valiable.id gives you the id for user
CbResume.last.set_global_valiable.id same as for CbResume Model
hope this help you !!!
If you're only using it from that model, it doesn't need to be global. Can be just a private method:
def update_game_index_file_url
files = FindFilesOnS3Job.perform_now("index.html", game_path)
self.update_attributes(url: files.first)
end
private
def game_path
"assets/#{id}/game"
end
How can I declare such varaible.
Variables don't behave this way. It has to be a method on some object. A shared one, if you want to use this logic outside of the model too. Something like this, perhaps:
module PathHelpers
def self.game_path(game)
"assets/#{game.id}/game"
end
end
class Game
def update_game_index_file_url
files = FindFilesOnS3Job.perform_now("index.html", PathHelpers.game_path(self))
end
end

Creating custom reusable method in rails 4

Guys today I'm trying to create global method for all my project models in rails 4
I created something like that under this path lib/query.rb
module Query
def custom my_query
self.where(my_query)
end
end
then added this code in this file lib/application.rb to allow rails to load the files under this path
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
then included my method in my model by using this command
include Query
now should every thing ready to use my custom method , but when I tried to call my method in the controller like that
def index
#users= Users.custom(params[:query])
end
I got the error
undefined method `custom'
what I should do now ??
why i got this error ??
I think you should use concern for your module. Add your file in app/models/concerns.
# app/models/concerns/query.rb
module Query
extend ActiveSupport::Concern
included do
#you can use a scope
scope :my_query, ->(just_a_param){ .... }
end
module ClassMethods
#or a method
def self.another_query
where(....)
end
end
end
Of course you need to include the module in your model. As concern erd default in rails, you no longer need to change config autoload paths.
As a class method, you'll need the "self."
def self.custom my_query
self.where(my_query)
end
EDIT: If you want this in all ActiveRecord models, you can add it as an initializer
#config/initializers/active_record_extensions.rb
class ActiveRecord::Base
def self.custom my_query
self.where(my_query)
end
end
If you just want this on a single class, a concern would work.
In your example, there is no reference given between your class Users and your method custom. First: if Users refers to a Ruby on Rails class it is probably called User (see also comment of japed). So change the call. Next, your User class must inherited from ActiveRecord else it would not be aware of the existence of 'where'. For details check your app/models/user.rb
Then Swards' suggestion should work for you. Stop your application and restart. Now it should work.
Guys I found the true way to make it
First my impropriety was the include that I set in the model
It should be extend Query
then it will work well
so the true code will be
create your method file under this path lib/query.rb
then set this code in it
module Query
def custom my_query
self.where(my_query)
end
end
then added this code in this file lib/application.rb
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
then extend the method in the model by using this command
extend Query
and in your controller query you can use the method like that
def index
#users= Users.custom(params[:query])
end
This is my solution, not exactly the 'Rails way', but using some sort of decorator pattern:
#user = CustomQuery.find_for(User.find(params[:search])).perform!
class CustomQuery
attr_reader :params, :klass
def initialize(klass)
#params = params
#klass = klass
end
def self.find_for(params)
CustomQuery.new(params)
find_model_for(params.tap {})
end
def perform!
return params unless params.nil?
klass.all
end
def find_model_for(klass)
#klass = klass
end
end
While I'm not sure about the process to create a global method, I can tell that your Ruby code is not valid:
def custom my_query
self.where(my_query)
end
It would need to be:
def custom (my_query)
self.where(my_query)
end

About strategy pattern and Rails

I want to incorporate the strategy pattern in my application.
I have stored under lib the following classes.
class Network
def search
raise "NO"
end
def w_read
raise "NO"
end
#...
end
AND
class FacebookClass < Network
def search
# FacebookClass specific...
end
def w_read
raise OneError.new("...")
end
end
AND
class TwitterClass < Network
def search
# TwitterClass specific...
end
def w_read
# TwitterClass specific...
end
def write
# TwitterClass specific...
end
end
Now I want to call the method search of TwitterClass from app/model/network_searcher.rb. How can I do that? Did I implemented the strategy pattern here successfully?
Going by the example in the Wikipedia, I think your app/model/network_searcher should be something like this
class NetworkSearcher
def initialize(search_class)
#search_class = search_class
end
def search_social
#search_class.search
end
def w_read_social
#search_class.w_read
end
def write_social
#search_class.write
end
end
Then in controller or where you want to invoke it, you can call like this:
search_class = TwitterClass.new # or FacebookClass.new
network_searcher = NetworkSearch.new(search_class)
network_searcher.search_social # or network_searcher.w_read_social or network_searcher.write_social
Also if you are keeping these classes in lib, for Rails 3, inorder to get these classes autoloaded, you need to add this line to config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
and also follow the naming convention for the filenames in Rails (for example TwitterClass should be named twitter_class.rb). Otherwise you will have to require these files wherever you are using these classes.
The strategy pattern is used to allow the algorithm to use to be selected at runtime. Without more details it's hard to say if this is appropriate to your problem. Assuming that it is then what you need is a way to set the search on your model and you can then use the selected algorithm elsewhere in your model. e.g.
class TheInformation
attr_writer :searcher
def other_method
..
# can use the selected searcher here
#searcher.search
..
end
end
Does that help?

Unable to access library files from controller in rails

I have created a new library file sampler.rb inside the lib folder. Consider this as the content of the file
module Sampler
def sample_tester
"test"
end
end
I have included it in the application_controller and added a require statement in the config\initializers. When I try to access the method sample_tester from my controllers, I get the following error
undefined local variable or method `sample_tester` for #<BlogsController:0xb8fbac8>
Am I missing something?
Since it doesn't look like you are creating an instance of this, my first guess is that you need to define it as a class method so that it can be called like this: Sampler.sample_tester.
In your file you could do it one of two ways:
# first way
module Sampler
def self.sample_tester
"test"
end
end
# second way
module Sampler
class << self
def sample_tester
"test"
end
end
The second way is nicer if you want to define a number of class methods.
if you want to have your module method defined as a class method you need to use extend instead of include:
module Mod
def bla
puts "bla"
end
end
class String
include Mod
end
String.bla rescue puts $! # => undefined method `bla' for String:Class
class String
extend Mod
end
puts String.bla # => bla

Rails 2.3.5: How does one access code inside of lib/directory/file.rb?

I created a file so I can share a method amongst many models in lib/foo/bar_woo.rb. Inside of bar_woo.rb I defined the following:
module BarWoo
def hello
puts "hello"
end
end
Then in my model I'm doing something like:
def MyModel < ActiveRecord::Base
include Foo::BarWoo
def some_method
Foo::BarWoo.hello
end
end
The interpreter is complaining that it expected bar_woo.rb to define Foo::BarWoo.
The Agile Web Development with Rails book states that if files contain classes or modules and the files are named using the lowercase form of the class or module name, then Rails will load the file automatically. I didn't require it because of this.
What is the correct way to define the code and what is the right way to call it in my model?
You might want to try:
module Foo
module BarWoo
def hello
puts "hello"
end
end
end
Also for calling you won't call it with Foo::BarWhoo.hello - that would have to make it a class method. However includeing the module should enable you to call it with just hello.
Files in subdirectories of /lib are not automatically require'd by default. The cleanest way to handle this is to add a new initializer under config/initializers that loads your library module for you.
In: config/initializers/load_my_libraries.rb Pick whatever name you want.
require(File.join(RAILS_ROOT, "lib", "foo", "bar_woo"))
Once it has been require'd, you should be able to include it at will.
The issue is twofold.
You need to use the outer Foo scope to define BarWoo
You have defined hello as an instance method, then tried to call it on the class.
Define your method using def self.hello instead of def hello
module Foo
module BarWoo
def self.hello
puts "hello"
end
end
end
You can also do
module Foo::Barwoo; end;

Resources