orry for the basics, but I'm having a hell of a time getting a very basic flow to work:
1) Define module with a method to save a url to a var (or return it)
2) Call that method in a controller to initialize the method
3) Have a view show that URL
NoMethodError in AuthController#oauth undefined method `oauthurl' for GetAccessToken:Module
Module: \lib\get_access_token.rb
module GetAccessToken
CONSUMER_TOKEN = { :token=>"mytokenstringwhichisreallylong", :secret=> "mysecretstringwhichisreallylong" }
def self.oauthurl
#oauthurl="https://us.etrade.com/e/t/etws/authorize?key=#{(CONSUMER_TOKEN[:token])}&token="
end
end
Controller: app\controllers\auth_controllers.rb
require 'get_access_token'
class AuthController < ApplicationController
include GetAccessToken
before_filter :oauthurl1
def oauthurl1
GetAccessToken.oauthurl
end
end
View: app\views\auth\oauth.html.erb
<% provide(:title, 'oAuth') %>
<h1>oAuth</h1>
<%= link_to "oAuth", #oauthurl %>
My higher level goal is to get the eTrade oAuth flow working, but I want to make sure I understand every line of code vs. taking someone else's and I can't get this very basic building block to work yet.
Add the following to config/application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**"]
Change your AuthController to:
class AuthController < ApplicationController
include GetAccessToken
def oauthurl1
GetAccessToken.oauthurl
end
end
Your module code will be
module GetAccessToken
CONSUMER_TOKEN = { :token=>"mytokenstringwhichisreallylong", :secret=> "mysecretstringwhichisreallylong" }
def self.oauthurl
"https://us.etrade.com/e/t/etws/authorize?key=#{(CONSUMER_TOKEN[:token])}&token="
end
end
and your controller code should be
require 'get_access_token'
class AuthController < ApplicationController
include GetAccessToken
def oauthurl1
#oauthurl = GetAccessToken.oauthurl
end
end
We need to initialize #oauthurl in the controller to use this variable in the view, else it will be nil.
With the generous help of the contributions above, this is how I finally resolved the error. I defined the instance variable in the controller instead of the model, and initialized the controller method using before_filer:
Model:\lib\test_module.rb
module TestModule
CONSUMER_TOKEN = { :token=>"myReallyLongToken", :secret=> "myReallyLongSecret" }
def self.testUrl
"https://us.etrade.com/e/t/etws/authorize?key=#{(CONSUMER_TOKEN[:token])}&token="
end
end
Controller: app\controllers\test_controller.rb
require 'test_module'
class TestController < ApplicationController
include TestModule
before_filter :testUrl1Init
def testUrl1Init
#testurl=TestModule.testUrl
end
end
View: \app\views\test\test.html.erb
<% provide(:title, 'test') %>
<h1>test</h1>
<%= link_to "test link", #testurl %>
Related
I have the following helper
module AvatarHelper
# Todo: set a defatul profile-image-path
DEFAULT_PROFILE_IMAGE_PATH = "http://image_here"
def avatar_path(user, size = 24)
..
end
def get_facebook_profile_pic user, size
..
end
def get_gravatar_path user, size
..
end
end
When I try to call the helper method in controller, it results in the following error:
undefined method `avatar_path' for AvatarHelper:Module
Here is my controller for reference:
class DashboardController < ApplicationController
before_action :authenticate_user!
def index
#dashboard = Dashboard.new(current_user)
puts AvatarHelper.avatar_path(current_user)
end
end
When I reference other helpers, I see they don't need to reference the helper elsewhere.
module TitleHelper
SITE_TITLE = 'My Site'
TITLE_SEPARATOR = ' ยท '
DESCRIPTION_CHARACTER_LIMIT = 140
def title(*parts)
parts << SITE_TITLE
provide(:title, parts.compact.join(TITLE_SEPARATOR))
end
end
I can then just add the title method directly in the view.
<% title 'myPage' %>
Module methods cannot be invoked directly. They should be included in the class to invoke. That's why they are called mixins(they can be mixed with others).
Here you can include the module in your controller.
class DashboardController < ApplicationController
include AvatarHelper
def index
#dashboard = Dashboard.new(current_user)
puts avatar_path(current_user)
end
end
def self.avatar_path(user, size = 24)
..
end
you are calling instance method add self before mthod will work for you.
Add the following code in your helper.
module AvatarHelper
extend ActiveSupport::Concern
Now you can directly call your method by name like
puts avatar_path(current_user)
I am having a action in application controller
def is_customer_logged_in?
!!session[:customer_id]
end
And in my view am trying to access the application_controller action like this
<% unless is_customer_logged_in? %>
some functions
<% end %>
The above code is a partial layouts.
This is the error message I am facing
undefined method `is_customer_logged_in?' for #<#<Class:0xb51a5300>:0xb5616484>
You can define it to be a helper method and you should be able to access that method in the view.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def is_customer_logged_in?
!!session[:customer_id]
end
helper_method :is_customer_logged_in?
end
try helper_method: is_customer_logged_in?
I'm trying to create a custom helper like this:
# app/controllers/my_controller.rb
class MyController < ApplicationController
helper :my
def index
puts foo
end
end
# app/helpers/my_helper.rb
module MyHelper
def foo
"Hello"
end
end
But, I got the following error:
undefined local variable or method `foo' for #<MyController:0x20e01d0>
What am I missing ?
Generally, I do the opposite: I use controller methods as helpers.
class MyController < ApplicationController
helper_method :my_helper
private
def my_helper
"text"
end
end
Helpers are accessed from the views, not the controllers. so if you try to put the following inside your index template it should work:
#my/index.html.erb
<%= foo %>
If you do want to access something from the controller, then you should use the include syntax instead of helper, but do not name it like a helper module in that case.
How about just including the helper as a mixin in the controller...
class MyController < ApplicationController
include MyHelper
def index
puts foo
end
end
Noob scoping issue, I imagine. :\
class ApplicationController < ActionController::Base
protect_from_forgery
#locations = get_locations
def get_locations
Location.where(:active => true).order('name').all
end
end
Error:
undefined local variable or method `get_locations' for ApplicationController:Class
Two questions:
1) What's with the error? Am I calling the method incorrectly?
2) How do I access this method from a sub-classed controller?
You're calling get_locations within the class scope, but the method is an instance method, not a class method. If for example you used def self.get_locations then you would be providing a class method, one of which you can use within the class scope (after you have defined it, not before like you're doing).
The problem here is the logic, what is this method for? What do you intend to use #locations for? If it's to go inside your application view, then you should put this method into the ApplicationHelper module, and call it from inside the relevant action. If you'd like it in another view on another controller and you'd like to use #locations inside your locations method, perhaps your setup might look something like this:
PagesController
class PagesController < ActionController::Base
def locations
#locations = Location.where(:active => true).order('name').all
end
end
locations.html.erb
<% #locations.each do |location| %>
<%= # do something with 'location' %>
<% end %>
If you'd like to use this inside of your application.html.erb you can simplify it quite some..
ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery
def locations
Location.where(:active => true).order('name').all
end
end
application.html.erb
<% locations.each do |location| %>
<%= # do something with location %>
<% end %>
The answer boils down to logic, and to really figure out exactly what you're looking for, more details would probably be required.
You're calling it from the class scope, not from an instance scope. more likely what you want is the following:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :setup_locations
private
def setup_locations
#locations = Location.where(:active => true).order('name').all
end
end
To make your original example work, you'd need to make #get_locations defined on self (which points to the class at definition), like so:
class ApplicationController < ActionController::Base
protect_from_forgery
#locations = get_locations
def self.get_locations
Location.where(:active => true).order('name').all
end
end
The problem with that code is that #locations will only be available from the class level as a class instance variable, which is comparable to a static variable in most other languages, and which probably isn't what you want.
I imagine that this line:
#locations = get_locations
... is trying to access the class level method get_locations and not the instance method.
The clue here is that the error message is showing that it can't find it on the class itself (ApplicationController:Class) and not an instance of that class. That means that you're in the class scope, not instance scope.
This would fix it:
def self.get_locations
Location.where(:active => true).order('name').all
end
Even the question is quite old, you can also call your controller action anywhere just by calling:
ApplicationController.new.get_locations
My app should render html, to answer when a user clicks ajax-link.
My controller:
def create_user
#user = User.new(params)
if #user.save
status = 'success'
link = link_to_profile(#user) #it's my custom helper in Application_Helper.rb
else
status = 'error'
link = nil
end
render :json => {:status => status, :link => link}
end
My helper:
def link_to_profile(user)
link = link_to(user.login, {:controller => "users", :action => "profile", :id => user.login}, :class => "profile-link")
return(image_tag("/images/users/profile.png") + " " + link)
end
I have tried such methods:
ApplicationController.helpers.link_to_profile(#user)
# It raises: NoMethodError (undefined method `url_for' for nil:NilClass)
and:
class Helper
include Singleton
include ActionView::Helpers::TextHelper
include ActionView::Helpers::UrlHelper
include ApplicationHelper
end
def help
Helper.instance
end
help.link_to_profile(#user)
# It also raises: NoMethodError (undefined method `url_for' for nil:NilClass)
In addition, yes, I KNOW about :helper_method, and it works, but i don't want to overload my ApplicationController with a plenty of that methods
helpers are just ruby modules which you can include in any controller just like any module.
module UserHelper
def link_to_profile(user)
link = link_to(user.login, {:controller => "users", :action => "profile", :id => user.login}, :class => "profile-link")
return(image_tag("/images/users/profile.png") + " " + link)
end
end
And, in your controller :
class UserController < ApplicationController
include UserHelper
def create
redirect_to link_to_profile(User.first)
end
end
Oki. Let's recap. You want access to certaint functions/methods, but you don't want those methods to be attached to current object.
So you want to make a proxy object, that will proxy/delegate to those methods.
class Helper
class << self
#include Singleton - no need to do this, class objects are singletons
include ApplicationHelper
include ActionView::Helpers::TextHelper
include ActionView::Helpers::UrlHelper
include ApplicationHelper
end
end
And, in controller:
class UserController < ApplicationController
def your_method
Helper.link_to_profile
end
end
The main disadvantage to this approach is that from the helper functions you won't have access to controller context (EG you won't have access to params, session, etc)
A compromise would be to declare those functions as private in the helper module, therefore, when you will include the module, they will also be private in the controller class.
module ApplicationHelper
private
def link_to_profile
end
end
class UserController < ApplicationController
include ApplicationHelper
end
, as Damien pointed out.
Update: The reason why you get the 'url_for' error is that you do not have access to controller's context, as stated above. You could force passing the controller as a parameter(Java-style ;) ) like:
Helper.link_to_profile(user, :controller => self)
and then, in your helper:
def link_to_profile(user, options)
options[:controller].url_for(...)
end
or event a bigger hack, presented here. However, i would reccomend the solution with making methods private and including them in the controller.
Take that! http://apotomo.de/2010/04/activehelper-rails-is-no-pain-in-the-ass/
That's exactly what you were looking for, dude.