How can I use an "outside" class on rails 3? - ruby-on-rails-3

So, I have this ruby file and I want to use it in my rails project, but I don't have a clue on where or how to start, I've read about include and require, some sites tell me to use require, some to use include, and even to use both, but that's it. I would like to know where to put the necessary code, how to use the file's methods and where to put the file in the project directory, because I want to call it from a view but I don't know if that is the best, I'm sorry if this is a dumb question but rails is still new for me. I appreciate all the help you can offer. Thanks for your time.
The file I'm trying to use is the one that converts numbers to words created by Faustino Vasquez limon and it's a full class:
numeros.rb
class Numlet
def initialize(numero)
#numero = numero.to_s.reverse.split("")
#i = 0
#j = 0
#parte1 = []
#parte2 = []
#especial = ""
#numlet = []
#bandera=0
#bandera1=0
#a =[["Uno","Dos","Tres","Cuatro","Cinco","Seis","Siete","Ocho","Nueve"],
["Diez","Veinte","Treinta","Cuarenta","Cincuenta","Sesenta","Setenta","Ochenta","Noventa"],
["Ciento","Doscientos","Trescientos","Cuatrocientos","Quinientos","Seiscientos","Setecientos","Ochocientos","Novecientos"]]
end
def especial
#numlet[#j] = case #especial
when "11"then "Once"
when "12"then "Doce"
when "13"then "Trece"
when "14"then "Catorce"
when "15"then "Quice"
when "16"then "Dieciseis"
when "17"then "Diecisiete"
when "18"then "Dieciocho"
when "19"then "Diecinueve"
when "21"then "Veintiun"
when "22"then "Veintidos"
when "23"then "Veintitres"
when "24"then "Veinticuatro"
when "25"then "Veinticinco"
when "26"then "Veintiseis"
when "27"then "Veintisite"
when "28"then "Veintiocho"
when "29"then "Veintinueve"
else return 0
end
end
def repetir
case #numero.length
when 0..3 then #parte1[0] = #numero[0..#numero.length]
when 4..6 then #parte1[0] = #numero[0..2];#parte1[1] = #numero[3..#numero.length]
when 7..9 then #parte1[0] = #numero[0..2];#parte1[1] = #numero[3..5]; #parte1[2] = #numero[6..#numero.length]
else return 0
end
end
def convierte
#bandera1=0
#i=0
case #bandera
when 1 then #numlet[#j]="mil";#j+=1
when 2 then (#parte2.length==1 and #parte2[0]==1) ? #numlet[#j]="millon" : #numlet[#j]="millones";#j+=1
end
#especial = [#parte2[#i+1],#parte2[#i]].to_s
if especial != 0
#i+=2
#j+=1
else
if #parte2[#i].to_s =="1"
#numlet[#j]="Un"
#i+=1
#j+=1
end
end
while #i < #parte2.length
if #parte2[#i].to_i ==0
#i+=1
#bandera1+=1
else
if #parte2.length != 1 and #bandera1 ==0
if #i == 1
#numlet[#j]="y"
#j+=1
end
end
#numlet[#j] = #a[#i][#parte2[#i].to_i-1]
if #i == 2 and #bandera1==2 and #numlet[#j]=="Ciento"
#numlet[#j]="Cien"
end
#j+=1
#i+=1
end
end
#bandera+=1
end
def termina
#numlet.reverse.join(" ")
end
def a_letra
if repetir != 0
#parte1.each do |#parte2|
convierte
end
print "#{termina}\n"
else
print "Este numero no puede ser convertido\n"
end
end
end
That is what i want to use from my app. Thank you for your time.

Since it's your own class and you want to use it in one of the Rails views, there's many ways of using that code.
My own way and you may or may not choose to do it this way would be to include that file in the lib directory and then require it in the helper file of the you view you want to include it in.
This would allow you to access methods and initializers from that file and you would be able to create methods in your helpers to use on your views.

Related

Adding a conditioned return in a Scope (be able to chain scopes in a scope depending on conditions)

I have a recurrent code with conditions in a new permission recently added code. It was not designed from the start, so it is a little messy:
#usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
# master puede ver todos, así que ignora los permisos
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# Si es admin y no tiene permisos establecidos
#usuarios = Usuario.where(id: nil)
else
# Lee de que niveles puedes mostrar los usuarios
#usuarios = #usuarios.del_nivel(usuario_actual.permiso.niveles)
end
end
if usuario_actual.es_admin_occ?
#usuarios = #usuarios.de_occ
end
I want to make it a scope this way:
#usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
#usuarios = #usuarios.permitibles(usuario_actual)
How can I make it work? I have currently this:
class Usuario < ActiveRecord::Base
scope :permitibles, lambda{ |usuario_actual|
# master can see everything, so, don't scope anything at all
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# return nothing if you don't have permissions
where(id: nil)
else
# this is a scope
del_nivel(usuario_actual.permiso.niveles)
end
if usuario_actual.es_admin_occ?
# this is a scope
de_occ
end
end
}
end
The problem is, inside the scope, that I don't know how to chain the other scopes, I mean, "de_occ" must be chained depending on the other condition, but right now this will will not work as is, because it will return only one scope instead of chaining "de_occ" to the first condition. How can I achieve that?
Thanks!
Ok, it's little problematic for me to go through your code. The best practice is not to use you mother langauge as a source of model and method names.
The basic approach for your problem would be to move the logic into a method and chains scopes / sqls. Here is a proof of concept:
scope :menores_de_edad, ->() {where(something: true)}
scope :del_nivel, ->(params) {where(field: param)}
scope :de_occ, ->() { ... }
def self.we_are_chaining_scopes
result = self.scoped
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# return nothing if you don't have permissions
result = result.menores_de_edad
else
# this is a scope
result = result.del_nivel(usuario_actual.permiso.niveles)
end
if usuario_actual.es_admin_occ?
# this is a scope
result = result.de_occ
end
end
result
end
You can make it even nicer by creating a service object for this query. Rough example:
class SpecificQuery
def initialize(relation = Model.scoped)
#relation = relation
end
private
def scoped_to(&block)
#relation = #relation.instance_eval(&block)
end
def scoped_behavior_method_one(param)
scoped_to { where(:something: param) }
end
def scoped_behavior_method_two(param)
scoped_to { ... }
end
end
And then you can chain scopes nicely as well + you're encapsulating the logic which should not necessarily belongs to your model. Also, it's easier to write specs :) I hope that helps.

How to stop a helper method from applying to a specific controller?

I have a helper_method that allows links to escape from a subdomain. However it is impacting my videos_controller, as it essentially seems to negate the 'current_event' method when not in the events controlller.
I've tried several dozen different ways over the last 4 days to make it so I can still escape my links from the subdomain, but still allow the videos_controller to work.
I think the best way to achieve this is to exclude the videos_controller from the helper method, but I'm not sure how (or if it is actually the best way forward - I'm obviously a noob!) Any suggestions please?! Relevant code below:
module UrlHelper
def url_for(options = nil)
if request.subdomain.present? and request.subdomain.downcase != 'www' and !options.nil? and options.is_a?(Hash) and options.has_key? :only_path and options[:only_path]
options[:only_path] = false
end
super
end
end
Videos_controller
def new
if current_event?
#video = current_event.videos.new
else
#video = Video.new
end
end
def create
if current_event.present?
#video = current_event.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
else
#video = current_user.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
end
if #video.save
flash[:success] = "Video uploaded!"
redirect_to root_url(subdomain: => current_event.name)
else
flash[:error] = "#{#video.errors.messages}"
render :new
end
end
current_event method
def current_event
if request.subdomain.present?
#event = Event.find_by_name(request.subdomain)
end
end
Did you take a look at this post yet?
You might want to create a new function test that only does something like
module UrlHelper
def test
puts "Test is called"
end
end
If that works you know its not including that fails but it has to be the method.
Otherwise you know the module is not included and you can narrow down the search.

ActiveRecord: Is it possible to get the number of DB queries executed in addition to total time in the Rails log?

For every request, I get this in the logs:
Completed 200 OK in 854ms (Views: 1.0ms | ActiveRecord: 17.0ms)
Is it possible to get it to also include the number of queries?
Something like:
Completed 200 OK in 854ms (Views: 1.0ms | ActiveRecord: 17.0ms | Queries: 10)
Ideally, I'd like all the "cached" ones to show up in that count too. Ie, even if the "cache" is saving me from "N+1" queries from hitting the DB, I still want to know I have a problem.
I'm fine with monkeypatching / manually editing something, since I really want this just for my dev box.
(If this can be made civilizedly so I can have it in production, that's even better, but if not, I'm fine with just having a manually modified Rails in my own machine)
Thanks!
Daniel
I know the ThinkingSphinx gem does something quite like this, adding the time spent running Sphinx queries to the summary in the log. You can probably do something similar ( maybe by making your own gem, since I bet other people would appreciate this functionality) to make the number of queries appear.
I haven't really looked hard at how it works, but it looks like modifications to ActionController and LogSubscriber are responsible:
lib/thinking_sphinx/action_controller.rb:
module ThinkingSphinx
module ActionController
extend ActiveSupport::Concern
protected
attr_internal :query_runtime
def cleanup_view_runtime
log_subscriber = ThinkingSphinx::ActiveRecord::LogSubscriber
query_runtime_pre_render = log_subscriber.reset_runtime
runtime = super
query_runtime_post_render = log_subscriber.reset_runtime
self.query_runtime = query_runtime_pre_render + query_runtime_post_render
runtime - query_runtime_post_render
end
def append_info_to_payload(payload)
super
payload[:query_runtime] = query_runtime
end
module ClassMethods
def log_process_action(payload)
messages, query_runtime = super, payload[:query_runtime]
messages << ("Sphinx: %.1fms" % query_runtime.to_f) if query_runtime
messages
end
end
end
end
lib/thinking_sphinx/active_record/log_subscriber.rb:
require 'active_support/log_subscriber'
module ThinkingSphinx
module ActiveRecord
class LogSubscriber < ActiveSupport::LogSubscriber
def self.runtime=(value)
Thread.current['thinking_sphinx_query_runtime'] = value
end
def self.runtime
Thread.current['thinking_sphinx_query_runtime'] ||= 0
end
def self.reset_runtime
rt, self.runtime = runtime, 0
rt
end
def initialize
super
#odd_or_even = false
end
def query(event)
self.class.runtime += event.duration
return unless logger.debug?
identifier = color('Sphinx Query (%.1fms)' % event.duration, GREEN, true)
query = event.payload[:query]
query = color query, nil, true if odd?
debug " #{identifier} #{query}"
end
def message(event)
return unless logger.debug?
identifier = color 'Sphinx', GREEN, true
message = event.payload[:message]
message = color message, nil, true if odd?
debug " #{identifier} #{message}"
end
def odd?
#odd_or_even = !#odd_or_even
end
def logger
return #logger if defined? #logger
self.logger = ::ActiveRecord::Base.logger
end
def logger=(logger)
#logger = logger
end
attach_to :thinking_sphinx
end
end
end
I hope this helps.

Rails 3 - creating own model and working with an others

I have two tables for checking views (visits of the page) - views of pic (PhotoView) in gallery and photographers(PhotographerView).
Because these two models (and tables) are the same, I want to create a model for them - something like:
class Func < ActiveRecord::Base
def self.check_views(model_view, data)
last_view = model_viewView.where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
model_view+View.new(...).save
model_view.increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
model_view+View.new(...).save
model_view.increment_counter(:views, data.id)
end
end #comparing dates
end
end
and call this method like:
#photo = Photo.find(params[:id])
Func.check_views('Photo', #photo)
When I try use it with the way above, I'll get the error undefined method `check_views' for Func(Table doesn't exist):Class
Could you give me a help, how to make it work?
Thank you
You can use ActiveRecord::Concern and modules to move the common functionality into one place as follows:
module CheckViews
extend ActiveSupport::Concern
module ClassMethods
# all class methods go here, if you don't have any just leave it blank
end
def check_views(data)
last_view = where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
##views_class.new(...).save
increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
##views_class.new(...).save
increment_counter(:views, data.id)
end
end #comparing dates
end
end
class Photo < ActiveRecord::Base
include CheckViews
end
you can now do the following:
#photo = Photo.find(params[:id])
#photo.check_views
I'd be very tempted to do this as a module extending the classes which want the Views functionality. Something like the following ought to work; but it's entirely untested and entirely unlike anything I've ever done before so it may be completely buggy. Fair warning.
module CheckViews
def self.extended(host_class)
host_class.class_variable_set("##views_class", "#{host_class}View".constantize)
end
def check_views(data)
last_view = where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
##views_class.new(...).save
increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
##views_class.new(...).save
increment_counter(:views, data.id)
end
end #comparing dates
end
end
class Photo < ActiveRecord::Base
extend CheckViews
...
end
(extend adds all the instance methods of the target Module as class methods of the calling class; so Photo gains Photo.check_views(data), and self in that function is the class Photo.)

Rails 3 - Multi-form Wizard - Trying to edit record does not save values

I am doing a multi-form wizard, following the steps provide by Ryan Bates. Creating a new record works, so I was trying to use the same logic for when I edit a record. However, the values that I change do not change -- when I edit something from the first form, go forward then backwards, my edits do not save. Here is the code in my controller:
def edit
session[:edit] = "Only change the fields you wish to edit"
#demographic = Demographic.find(params[:id])
session[:demographic_params] ||= {}
end
def update
session[:demographic_params].deep_merge!(params[:demographic]) if params[:demographic]
#demographic = Demographic.find(params[:id])
#demographic.current_step = session[:demographic_step]
if params[:back_button]
#demographic.previous_step
elsif #demographic.last_step?
#demographic.update_attributes(params[:demographic])
updated = true
else
#demographic.next_step
end
session[:demographic_step] = #demographic.current_step
if not updated
render "edit"
else
session[:demographic_params] = session[:demographic_step] = nil
flash[:notice] = "Entry entered successfully"
redirect_to demographic_path
end
end
What should I change that allows for saving the edits?
I don't know if this will work, but I think that should be something like this to save on every "step change":
def update
session[:demographic_params].deep_merge!(params[:demographic]) if params[:demographic]
#demographic = Demographic.find(params[:id])
#demographic.current_step = session[:demographic_step]
#demographic.update_attributes(params[:demographic])
if params[:back_button]
#demographic.previous_step
elsif #demographic.last_step?
updated = true
else
#demographic.next_step
end
session[:demographic_step] = #demographic.current_step
if not updated
render "edit"
else
session[:demographic_params] = session[:demographic_step] = nil
flash[:notice] = "Entry entered successfully"
redirect_to demographic_path
end
end
I.e., move the #demographic.update_attributes outsite the "step-by-step" logic.
So, I think that you should walk this way to solve your problem.
Hope this helps.