Can't access custom helper functions made within the file - Sinatra - ruby

I have this helper within my 'app.rb' file, which is used to get the current user object.
helpers do
def get_current_user(column, value)
user = User.where(column => value).first
return user
end
end
get '/' do
user = get_current_user(:id, params[:id])
end
This is what i did in irb:
irb(main):001:0> require './app'
=> true
irb(main):007:0> user = get_current_user(:id, 2)
NoMethodError: undefined method `get_current_user' for main:Object
from (irb):7
from /usr/bin/irb:12:in `<main>'
I don't understand why i can't access the helper methods from irb. Should i explicitly include the helpers or something? If so, why? Because i put them under the same file, under the same class.

get_current_users is metaprogrammed through the helpers method to be an instance method of App. So, if app.rb looks something like this:
require 'sinatra/base'
class App < Sinatra::Base
helpers do
def get_current_user
puts "here!"
end
end
end
...then from irb you can invoke get_current_user on an instance of App like this:
>> require './app'
>> App.new!.get_current_user
here!
=> nil
>>
(If you're wondering why that's new! and not new like most sane ruby code, read this answer.)

Related

How do I use instance variables initialized in my initialize method in other methods?

This is what my class looks like:
require 'oga'
require 'net/http'
require 'pry'
module YPCrawler
class PageCrawler
def initialize(url)
#url = 'http://www.someurl.com'
end
def get_page_listings
body = Net::HTTP.get(URI.parse(#url))
document = Oga.parse_html(body)
bizlistings = document.css('div.result')
binding.pry
end
end
end
Yet when I get thrown into pry, I see this:
[1] pry(YPCrawler::PageCrawler)> #url
=> nil
[2] pry(YPCrawler::PageCrawler)> body
NameError: undefined local variable or method `body' for YPCrawler::PageCrawler:Class
from (pry):2:in `<class:PageCrawler>'
[3] pry(YPCrawler::PageCrawler)> document
NameError: undefined local variable or method `document' for YPCrawler::PageCrawler:Class
from (pry):3:in `<class:PageCrawler>'
[4] pry(YPCrawler::PageCrawler)> bizlistings
NameError: undefined local variable or method `bizlistings' for YPCrawler::PageCrawler:Class
from (pry):4:in `<class:PageCrawler>'
[5] pry(YPCrawler::PageCrawler)> url
NameError: undefined local variable or method `url' for YPCrawler::PageCrawler:Class
Did you mean? URI
from (pry):5:in `<class:PageCrawler>'
[6] pry(YPCrawler::PageCrawler)> #url
=> nil
Why can I not access #url that was initialized in my def initialize method?
Edit 1
Added Screenshots of what my code and the terminal PRY session really look like, since there was some disbelief about the position of my binding.pry.
Edit 2
My main lib/yp-crawler.rb file looks like this:
require_relative "yp-crawler/version"
require_relative "yp-crawler/page-crawler"
require_relative "yp-crawler/listing-crawler"
module YPCrawler
end
So the code that is run above is my yp-crawler/page-crawler.rb file, which I included in my lib/yp-crawler.rb file.
Edit 3
Here is a recording of my entire workflow. Please tell me what I am missing:
https://www.dropbox.com/s/jp1abthfkiplb4p/Pry-not-cooperating.webm?dl=0
I bet your code looks as follows:
module YPCrawler
class PageCrawler
attr_reader :url
def initialize(url)
#url = 'http://www.someurl.com'
end
def get_page_listings
body = Net::HTTP.get(URI.parse(#url))
document = Oga.parse_html(body)
bizlistings = document.css('div.result')
end
binding.pry
end
end
Even though you might have moved the binding.pry into method, most likely you did not reload the console, so it executes the "wrong" version.
From your screenshots it is clear that either file is not reloaded or you just made changes to wrong file.

Set Up for RSpec in a Sinatra modular app

This is my first attempt with Sinatra. I built a simple classic app, set up RSpec for it, and got it working. Then, I tried to go modular, in a MVC fashion. Even though the app works in the browser, RSpec throws a NoMethodError. I've read Sinatra docs regarding RSpec, also searched a lot here in SO, but I can't find where the bug is. Any clue?
Thank you very much in advance.
Here are my relevant files:
config.ru
require 'sinatra/base'
Dir.glob('./{app/controllers}/*.rb') { |file| require file }
map('/') { run ApplicationController }
app.rb
require 'sinatra/base'
class ZerifApp < Sinatra::Base
# Only start the server if this file has been
# executed directly
run! if __FILE__ == $0
end
app/controllers/application_controller.rb
class ApplicationController < Sinatra::Base
set :views, File.expand_path('../../views', __FILE__)
set :public_dir, File.expand_path('../../../public', __FILE__)
get '/' do
erb :index
end
end
spec/spec_helper.rb
require 'rack/test'
# Also tried this
# Rack::Builder.parse_file(File.expand_path('../../config.ru', __FILE__))
require File.expand_path '../../app.rb', __FILE__
ENV['RACK_ENV'] = 'test'
module RSpecMixin
include Rack::Test::Methods
def app() described_class end
end
RSpec.configure { |c| c.include RSpecMixin }
spec/app_spec.rb
require File.expand_path '../spec_helper.rb', __FILE__
describe "My Sinatra Application" do
it "should allow accessing the home page" do
get '/'
expect(last_response).to be_ok
end
end
The error
My Sinatra Application should allow accessing the home page
Failure/Error: get '/'
NoMethodError:
undefined method `call' for nil:NilClass
# ./spec/app_spec.rb:5:in `block (2 levels) in <top (required)>'
I'm guessing you're following this recipe, correct?
The described_class in this line:
def app() described_class end
is meant to be the class under test, in this case ZerifApp. Try it like so:
def app() ZerifApp end
EDIT
It turns out the above answer is not correct about what described_class does. I assumed it was a placeholder -- actually it is an RSpec method that returns the class of the implicit subject, that is to say, the thing being tested.
The recipe at the link is misleading because of the way it recommends writing the describe block:
describe "My Sinatra Application" do
This is valid RSpec, but it does not define the subject class. Executing described_class in an example for this block will return nil. To make it work, replace the describe block:
describe ZerifApp do
Now described_class will return the expected value (ZerifApp)
https://pragprog.com/book/7web/seven-web-frameworks-in-seven-weeks
It has some source code to get some ideas from.
This has code example too. https://github.com/laser/sinatra-best-practices

Why do I get the error uninitialized constant Stuff::HTTParty?

I have the HTTParty gem on my system and I can use it from within rails.
Now I want to use it standalone.
I am trying:
class Stuff
include HTTParty
def self.y
HTTParty.get('http://www.google.com')
end
end
Stuff.y
but I get
$ ruby test_httparty.rb
test_httparty.rb:2:in `<class:Stuff>': uninitialized constant Stuff::HTTParty (NameError)
from test_httparty.rb:1:in `<main>'
07:46:52 durrantm Castle2012 /home/durrantm/Dropnot/_/rails_apps/linker 73845718_get_method
$
You have to require 'httparty':
require 'httparty'
class Stuff
include HTTParty
# ...
end
Its all because of the include which exists with in the class
If you include a class with a module, that means you're "bringing in" the module's methods as instance methods.
If you need more clarity on include and require
I request you to refer to this wonderful SO Posting
What is the difference between include and require in Ruby?
Here is an example which I have taken from the same posting
module A
def say
puts "this is module A"
end
end
class B
include A
end
class C
extend A
end
B.say => undefined method 'say' for B:Class
B.new.say => this is module A
C.say => this is module A
C.new.say => undefined method 'say' for C:Class

How to use alias_method in Haml to escape html?

What I want to do is using an alias method (defined in a ruby file) in Haml view.
I defined an alias method like following:
require 'sinatra'
require 'sinatra/base'
require 'data_mapper'
require 'haml'
helpers do
include Haml::Helpers
alias_method :h, :html_escape
end
class App < Sinatra::Base
use Rack::MethodOverride
# ...
end
Then I used method h() in a Haml view like following:
- #notes.each do |note|
%article{:class => note.complete? && "complete"}
%p
=h note.content
But I got an error when I opened the page:
NoMethodError - undefined method `h' for #:
...
When I use Haml::Helpers.html_escape() directly on the haml file, there's no problem:
%p
= Haml::Helpers.html_escape note.content
How can I use my alias method in haml files without errors?
Thanks for any advices or corrections to this questions.
Your helpers are getting defined in Application. Instead define them in your class like this:
class App < Sinatra::Base
helpers do
include Haml::Helpers
alias_method :h, :html_escape
end
# ...
end
or in Base like this:
Sinatra::Base.helpers do
include Haml::Helpers
alias_method :h, :html_escape
end

What's the proper way to mock Rails 3 routes and controllers in a plugin test?

I have an old pre-Rails 3 plugin whose tests will no longer run under Rails 3. The test looks something like this:
class TestController < ActionController::Base
def test_action; render :nothing => true; end
end
TestController.view_paths = [File.dirname(__FILE__)]
ActionController::Routing::Routes.draw {|m| m.connect ':controller/:action/:id' }
class TestControllerTest < ActionController::TestCase
context "test_action" do
should "do something" do
lambda { post :test_action }.should change { Model.count }
end
end
end
Running this test gets me:
uninitialized constant ActionDispatch::Routing::Routes (NameError)
When I use with_routing, which I thought was the new way of doing test routing, like so:
should "do something" do
with_routing do |set|
set.draw { |m| m.connect ':controller/:action/:id' }
lambda { post :test_action }.should change { Model.count }
end
end
I get:
NameError: undefined local variable or method `_routes' for TestController:Class
What am I missing? My test helper requires:
require 'rubygems'
require 'active_record'
require 'active_record/version'
require 'active_record/fixtures'
require 'action_controller'
require 'action_dispatch'
require 'action_view'
require 'test/unit'
require 'shoulda'
require 'mocha'
Ideas? Thanks!
You just need to draw the routes on Rails.application
Rails.application.routes.draw do
# Fun times
end
Edit: Uh, sorry, this won't work on rails 3, but maybe you upgraded already?
https://relishapp.com/rspec/rspec-rails/v/3-6/docs/controller-specs/engine-routes-for-controllers
You didn't specify any test framework, so I'll just mention that RSpec gives you routes method in type: :controller and type: :routing specs so you could do something like
before do
routes.draw do
get ':controller/:action/:id' => 'controller#action'
end
end

Resources