setting up controller for test - rubymotion

i'm trying to write a functional test for my controller in rubymotion using bacon.
in my controller i have some code that populates some data:
def viewWillAppear(animated)
song_text.text = chant.song_text
...
end
i am setting the chant variable when i push that controller to the navigation-controller.
this works fine in the app, but when i try to do that in a before-block of the spec it does not work, because viewWillAppear gets called before the block and it fails with a NoMethodError: undefined method 'song_text' for nil:NilClass.
is there some way to handle this situation? is there some other way to populate the data or use a different method than viewWillAppear?

I've experience a similar issue that was solved by calling the super method in the viewWillAppear method

The RubyMotion support answered my support ticket indicating, that this is the expected behavior of controllers in bacon.
I worked around the whole thing by stubbing my class under test in the bacon spec like so:
# spec/chant_controller_spec.rb
class ChantControllerStub < ChantController
def chant
#chant ||= create_chant
end
end
describe "ChantController" do
tests ChantControllerStub
it "displays a chant" do
view('verse').should.not == nil
end
end

Related

In Rails4, using Trailblazer, how do I access the current_user

We are building a Rails4 app using Trailblazer. I have never worked with Trailblazer before and I am confused about how to do things.
We are building an auction site. I was previously using a traditional controller, and this route endpoint was working fine:
def bill
#profile = Profile.find_by user_id: current_user_id
#current_order = Order.order(created_at: :desc).find_by(user_id: current_user_id)
#batch = #current_order.batch
if #batch.nil?
puts "There was no batch linked to the current order of #{#current_order.id}"
flash[:error] = "We are sorry, but we could not determine which batch your order belongs to."
else
#price_shown_to_customer = #batch.price + ENV["FUELBID_FEE_PER_GALLON"].to_f
#amount = #current_order.quantity * #price_shown_to_customer
end
But now I'm suppose to create this as a Trailblazer api, using a Representer class.
So in routes.rb I added something for "charges":
namespace :api do
get '/price' => 'info#info'
post '/order' => 'orders#create'
get '/charges' => 'charges#bill'
end
I created this Api but copying-and-pasting another:
module Api
class ChargesController < ApiApplicationController
respond_to :json
def bill
respond_with OpenStruct.new.extend(ChargesRepresenter)
end
end
end
I tested the above with a simple Representer and it all worked fine, so everything is good up to this point. If I return simple data from the Representer, then I can see it fine here:
http://localhost:3000/api/charges.json
But I need to get the current_user. How is this done? Right now, this does not work:
module ChargesRepresenter
include Roar::JSON
collection :price_shown_to_customer
def price_shown_to_customer
current_order = Order.order(created_at: :desc).find_by(user_id: current_user_id)
puts "current_order"
puts current_order.id
batch = current_order.batch
batch.price + ENV["FUELBID_FEE_PER_GALLON"].to_f
end
end
current_user_id exists in my traditional controllers because we set up Devise and so my traditional controllers inherit it:
class ChargesController < SecuredController
But is there any way to get it in a Trailblazer Representer?
Hope this answer is not too late.
If you can switch to Decorator pattern instead of a Module.
Representer really doesn't need to know and doesn't care if it is called from controller or console or test. All it needs is a hash to build your json object from. So you can just pass another attribute called current_user_id to your Representer and then use it inside r presenter like you do.
FYI:
If you need a more immediate response you can also copy your question to https://gitter.im/trailblazer/chat . There are usually several people hanging out there. But it's also good to post a question here for posterity.

Overriding Devise::RegistratoinsController

So I am trying to override Devise::RegistrationsController which they do have wiki for and tons of tutorial out there. The one thing that I can not find is the best implementation of how to override the controller whilst implementing the require admin approval feature as well.
I think I got the hang of it but before I go any further (from all the reading on the Devise's source code) I want to know, on the registrations controller there's a line that does:
resource.active_for_authentication?
However, on the Sessions controller it's just this:
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
What I want to know is, if it's not confirmed or the active_for_authentication returns false, where or how does the session controller check this? I tried tracing back the source code but no luck.
So anyone who's very familiar with Devise perhaps you could answer my question? Thank you.
After authenticating a user and in each request, Devise checks if your model is active by calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance, :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
You can overwrite this method yourself, but if you do, don't forget to call super:
def active_for_authentication?
super && special_condition_is_valid?
end
Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using the inactive_message method. You can overwrite it as well:
def inactive_message
special_condition_is_valid? ? super : :special_condition_is_not_valid
end

Why is Digest::SHA1 preventing proper annotation of a model?

I am using annotate in my app and all models are successfully annotated except for user.rb, which shows the following error when I annotate:
Unable to annotate user.rb: wrong number of arguments (0 for 1)
Outside of annotating, everything else works fine. User creation, updating, deletion, login, sign out, it all works properly. I have determined that the problem is with the Digest::SHA1, which I use to create session tokens, as demonstrated below in the snippet from user.rb.
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.hash(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
remember_token = User.hash(User.new_remember_token)
end
If I remove the second (def User.hash(token)) and instead do the following:
def User.new_remember_token
SecureRandom.urlsafe_base64
end
private
def create_remember_token
remember_token = Digest::SHA1.hexdigest(User.new_remember_token.to_s)
end
then annotate is happy and successfully annotates user.rb. However, this isn't really the ruby way as my session helper utilizes that User.hash(token) call several times. What am I not understanding about Digest::SHA1.hexdigest or the way that I am utilizing it?
Looks like you're working through The Rails Tutorial.
The likely reason you're seeing issues with your User.hash method is nothing to do with Digest::SHA1, but is because the method itself is inadvertently overriding Ruby's Object#hash method, which is giving you some cryptic errors. Link to Github issue about it.
So, like this commit to the Sample App repository, rename all your instances of User.hash to User.digest and hopefully that should fix your errors.

Rails: testing custom classes with RSpec

Yea, I know that this question is silly, newbee and simple, but I still can't figure it out.
I've created a class (in app/minions/ directory) to parse auth hashes from 3rd-party services (like google, twitter, etc.). It looks like this.
class AuthHash
def initialize(hash)
#hash = hash
#provider = hash[:provider]
#uid = hash[:uid]
create_user_hash
end
def create_user_hash
#user_hash = send("parse_hash_from_" << #hash[:provider], #hash)
end
def credentials
{provider: #provider, uid: #uid}
end
def user_hash
#user_hash
end
private
# parse_hash_from_* methods here
end
I've added that directory to the autoload path, so I can use it in my controllers. Now I want to write some tests for it.
I'm using RSpec with FactoryGirl for testing. So I started by adding a factory to spec/factories/ called auth_hashes.rb but I can't define a hash as a field in a factory.
So I moved the declaration to the spec/minions/auth_hash_spec.rb.
require 'spec_helper'
describe AuthHash do
before_each do
auth_hash = AuthHash.new({:provider=>"google_oauth2",:uid=>"123456789",:info=>{:name=>"JohnDoe",:email=>"john#company_name.com",:first_name=>"John",:last_name=>"Doe",:image=>"https://lh3.googleusercontent.com/url/photo.jpg"},:credentials=>{:token=>"token",:refresh_token=>"another_token",:expires_at=>1354920555,:expires=>true},:extra=>{:raw_info=>{:id=>"123456789",:email=>"user#domain.example.com",:verified_email=>true,:name=>"JohnDoe",:given_name=>"John",:family_name=>"Doe",:link=>"https://plus.google.com/123456789",:picture=>"https://lh3.googleusercontent.com/url/photo.jpg",:gender=>"male",:birthday=>"0000-06-25",:locale=>"en",:hd=>"company_name.com"}}})
end
end
But still it does not seem to work.
I know this should be alot simpler then I'm trying to do, but I can't figure it out.
Add something like this to that new spec (spec/minions/auth_hash_spec.rb) file at the top:
require Rails.root.to_s + '/app/minions/myhash.rb'
And then write your tests.

Minitest - test class in Rails 4

I am trying to use Minitest in a fresh Rails 4 install. My understanding is that if I have a class that doesn't inherit from ActiveRecord then I should be able to use Minitest itself, without Rails integration:
#test/models/blog.rb
require "minitest/autorun"
class Blog < Minitest::Unit::TestCase
def setup
#b = Blog.new
end
def test_entries
assert_empty "message", #b.entries
end
#app/models/blog.rb
class Blog
attr_reader :entries
def initialize
#entries = []
end
I run the test with ruby test/models/blog.rb.
My problem comes with the setup method. If I don't include an entry for my blog, the tests fails with the message that there are the wrong number of arguments in setup. If I include an entry in my setup message #b = Blog.new entries: "Twilight", my test fails in the test_entries method because entries is an undefined method.
You have a couple problems. First, you are not requiring "test_helper", which means that rails isn't getting loaded when you run this test, which means that the mechanism rails uses to resolve missing constants isn't loaded. You will either need to require the helper or require the blog file directly. Second, you are overwriting the constant you want to test with the test, which is why you are getting confusing messages. Name the test class BlogTest instead to avoid this.
This is what I think you are trying to do:
require "minitest/autorun"
require "models/blog" # Assuming "app" is in your load path when running the test
#require "test_helper" # Or require this instead if you need to use DB
class BlogTest < Minitest::Unit::TestCase
def setup
#b = Blog.new
end
def test_entries
assert_empty #b.entries, "Blog entries should be empty"
end
end