calling classes in /lib from controller actions - ruby-on-rails

hi i am a bit stuck with this. what i am going to work out is that i have a file called ticket_pdf.rb in lib/ directory which i am planning to generate some invoice PDFs for my app. I want to call a function of this class to generate the PDFs from my controller actions.
the ticket_pdf.rb looks like this
class TicketPDF
def generate_pdf (purchase)
puts "Ticket ID = #{purchase.ID}"
end
end
in a controller I action i do this.
class Customer::MyController < ApplicationController
require 'ticket_pdf'
def show
ticket = TicketPDF.new
end
end
when i try to create an object like this it give me a 500 error like this one.
uninitialized constant Customer::MyController::TicketPDF
what i am doing wrong here ?

Try
ticket = ::TicketPDF.new
You have created TicketPDF in the top level namespace.

Related

How does a controller class access a model class?

How does this random controller class
class RandomController < ApplicationController
def index
#user = User.all
end
end
access the User class? I've been searching for the connection in the source files, but I can't seem to find a logical explanation.
Rails has 'constant autoloading', so you don't need to add require 'user' to the top of your file.
http://guides.rubyonrails.org/autoloading_and_reloading_constants.html
When Rails encounters a missing constant, it tries to load a file with a filename based on the constant's name. This nearly always works smoothly... C-;

In Rails, where to put useful functions for both controllers and models

Suppose I have a function trim_string(string) that I want to use throughout my Rails app, in both a model and a controller. If I put it in application helper, it gets into the controller. But application helper isn't required from within models typically. So where do you put common code that you'd want to use in both models and controllers?
In answer to the specific question "where do you put common code that you'd want to use in both models and controllers?":
Put it in the lib folder. Files in the lib folder will be loaded and modules therein will be available.
In more detail, using the specific example in the question:
# lib/my_utilities.rb
module MyUtilities
def trim_string(string)
do_something
end
end
Then in controller or model where you want this:
# models/foo.rb
require 'my_utilities'
class Foo < ActiveRecord::Base
include MyUtilities
def foo(a_string)
trim_string(a_string)
do_more_stuff
end
end
# controllers/foos_controller.rb
require 'my_utilities'
class FoosController < ApplicationController
include MyUtilities
def show
#foo = Foo.find(params[:id])
#foo_name = trim_string(#foo.name)
end
end
It looks like you want to have a method on the String class to "trim" itself better than a trim_string function, right? can't you use the strip method? http://www.ruby-doc.org/core-2.1.0/String.html#method-i-strip
You can add new methods to the string class on an initializer, check this In Rails, how to add a new method to String class?
class String
def trim
do_something_and_return_that
end
def trim!
do_something_on_itself
end
end
That way you can do:
s = ' with spaces '
another_s = s.trim #trim and save to another
s.trim! #trim itself
but check the String class, it looks like you already have what you need there

How to use and where to put code not part of MVC

I wrote ruby code which pulls content from Google API. It works as a standalone example.rb file. I need to add this to my RoR app. What is the standard way to do it? How should I call this code from the controller? Should I add this code in some model file, keep the code in /lib folder, or put the code in /vendor/plugins folder?
Either extract it out into a gem, or you could put it in lib if you wanted.
If you take the second approach, here's an example. Say you have it in a module (Google)
#lib/google.rb
module Google
class Uploader
def initialize
...
end
def foo
...
end
end
...
end
in your controller
require 'google'
class MyController < ApplicationController
def new
uploader = Google::Uploader.new # do whatever here
uploader.foo
end
end
There are many ways to modify / use this module approach, the given code is only one possibility.

How does including a module work inside a controller?

If I do:
rails generate scaffold account/user username
I get a controller that looks like this:
class Account::UsersController < ApplicationController
def index
#account_users = Account::User.all
end
...
end
If I include the Account Module, then it looks like all the database calls don't need to be prefixed with "Account::". I.e.
class Account::UsersController < ApplicationController
include Account
def index
#account_users = User.all #this works because I included the Account Module above
end
...
end
Now if I were to move my
controllers/account/users_controller.rb
file to:
controllers/admin/account/users_controller.rb
The file looks like this (note: I also corrected my routes file after this move):
class Admin::Account::UsersController < ApplicationController
include Account
def index
#account_users = User.all #this call does not work now
end
...
end
But I get an error saying "uninitialized constant Admin::Account::UsersController::User"
It looks like rails is trying to make a database call on the "User" model without the "Account::" module in front of it.
So how does including modules in controllers work? Why does this not work when I move my controller into a different file (and leave the model in the same location from the generated scaffold) but it works with the scaffold generated files? How can I fix this issue?
Resolving the name of a module is done relative to the current module. Try and change it to:
include ::Account
or
include ::Admin::Account
(depending on the module in which your User model is defined)
This will tell ruby to look in the global namespace for the module Account
I guess I didn't realize you can just explicitly require the path to the module you would like to include. I learned this after reading up on modules some more...
So adding an explicit call to "require 'account/user'" just outside the controller class makes it so including the module in the controller works.

Including reopened class inside controller

I want to add custom methods to the Recurly::Account class by reopening it, and then use it in my controller.
something like this:
#reopen class
class Recurly::Account
#my custom method
def my_meth_1
end
end
class MyController
def index
account = Recurly::Account.find( ... ) #gem method
account.my_meth_1 #my custom method
end
end
In which file should I reopen the Recurly::Account class and how should it be included in my controller?
I think lib folder is a good place for this.
Simply create a file like this
# lib/recurly.rb
class Recurly::Account
def my_meth_1
end
end
how should it be included in my controller?
You will probably need to turn on autoloading from lib, see this topic how to do it Rails 3 autoload. After that, you can call it directly from controller.

Resources