Rails 3 NameError (uninitialized constant <controllerName>) - ruby-on-rails

I get a NameError uninitialized constant WorkoutLog when attempting to access a non-resourceful action on a controller.
My controller looks as follows:
class WorkoutLogController < ApplicationController
def index
# random code
end
def on_date
# random code
end
end
My Routes File:
match "workout_log/:date", :controller => "workout_log", :action => "on_date", :as => "log_on_date"
match "workout_log", :controller => 'workout_log', :action => 'index'
And then I have a my link_to as such:
<%= link_to "View Log", log_on_date_path(:date => Date.today.strftime('%d-%B-%Y')), :remote => true, "data-type" => "html" %>
The WorkoutLogController has no model behind it - it's just a controller. However, I can't perform a request on the on_date because it throws the following error:
NameError (uninitialized constant WorkoutLog):
When I run rake routes it seems to be fine as it generates the following:
log_on_date /workout_log/:date(.:format) {:controller=>"workout_log", :action=>"on_date"}
workout_log /workout_log(.:format) {:controller=>"workout_log", :action=>"index"}
I can't wrap my head around what the issue is (especially after spending the past night trying to figure it out). Is rails looking for a model to associate with it and failing to do so?

I figured out the issue. It had to do with declarative_authorization.
Since I had not copied the code 100%, I left out the following from my controller code pasted above:
filter_resource_access
declarative_authorization uses this for resourceful routes - which was not my case. I've since switched it to filter_access_to :all and it works fine. I got to the root of the problem by creating the file workout_log.rb in my models:
class WorkoutLog
end
Then when I issued a request to the index and on_date actions, it gave me the error that it could not find ActiveModel methods on WorkoutLog, which in turn pointed me to the filters on the WorkoutLogController.
If you look under Examples > Controller at the declarative_authorization page on GitHub, it'll provide the necessary info.
Hope this helps anyone else who has this issue!

Related

Devise - Allow both individual and admin user creation

I have seen the few links on here regarding this topic but as yet have been unable to crack the problem. I want my application to allow users to register but also to register other users. So far my code lucks like so (though at this point I'm not sure I'm even on the right path and have probably included stuff which is not required just to make it work):
routes.rb
resources :devise
devise_for :users, path: 'devise'
devise_scope :user do
get 'users/registrations/admin_new' => 'devise/registrations#admin_new'
post 'users/registrations/admin_create' => 'devise/registrations#admin_create'
end
These are the two methods I have referenced in my route.
controllers/user/registration_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def admin_new
puts "---------------"
#user = User.new
end
def admin_create
puts "---------------"
end
end
My view is as follows but shortened so as not to include all the fields:
views/devise/registrations/admin_new.html.haml
= simple_form_for(User.new, url: users_registrations_admin_create_path(User.new)) do |f|
...
This set up has gotten me to the point that the url:
http://localhost:3000/users/registrations/admin_new
loads the form alright however the puts I inserted does not appear in my console when it loads which is strange. Also i previously had the form as:
= simple_form_for(#user, url: users_registrations_admin_create_path(#user)) do |f|
...
however this resulted in the error:
undefined method `model_name' for nil:NilClass
which is why I changed to User.new instead of #user. When i submit the form it returns the error:
The action 'admin_create' could not be found for Devise::RegistrationsController
I'm at a loss as to why this is. I'm also unsure as to whether the structure of my devise is correct given the controllers are contained within a users folder while the views are contained with a devise folder. Any help on this would be greatly appreciated.
your route is problem.
post 'users/registrations/admin_create' => 'devise/registrations#admin_create'
which means this route to admin_create action in Devise::RegistrationsController
so router find a action in Devise::RegistrationsController but action "admin_create" exists in Users::RegistrationsController,
change
'devise/registrations#admin_create'
=> 'user/registrations#admin_create'
update1
I check your route out.
assigned route path to controller in 'controllers/devise/registrations_controller.rb'
post 'users/registrations/admin_create' => 'devise/registrations#admin_create'
PREFIX users_registrations_admin_create
URL PATTERN /users/registrations/admin_create(.:format)
Controller&Action devise/registrations#admin_create
assigned route path to controller in 'controllers/user/registrations_controller.rb'
post 'users/registrations/admin_create' => 'user/registrations#admin_create'
PREFIX users_registrations_admin_create
URL PATTERN /users/registrations/admin_create(.:format)
Controller&Action user/registrations#admin_create
only 'devise' controller name changed to 'user' in route, then fine.

Dynamically creating controller actions in Rails 5

I'm trying to set up dynamic routing in a Rails 5.1.4 api. Originally, I had all my dynamic routes pointing to a single action, which works just fine. The problem came when I attempted to use the swagger-docs gem, which requires a separate action for each entry in order to generate the necessary json for swagger ui. So, I figured I could simply dynamically create the methods and point the routes at them. As far as I can tell, the methods are not being created and I don't understand why. Even if I drop my debugger into the loop that cycles through my sections, it never gets triggered. I deeply appreciate any help on this.
routes.rb
Section.active.all.each do |section|
get "/#{section.url}", :to => "sections##{section.url}", defaults: { id: section.id }
end
sections_controller.rb
class SectionsController < ApplicationController
Section.active.all do |section|
define_method :"#{section.url}" do
#some things
end
end
end
development.rb
config.eager_load = true
If I call:
SectionsController.action_methods
=> #<Set: {}>
I ended up just making the section_url a param, pointing everything to the show action and adding the possible section urls in the docs description.
routes.rb
get "/:section_url", to: "sections#show"
#must be at the end of the routes definitions
sections_controller.rb
swagger_api :show do
summary "Returns Section Items"
param :path, :section_url, :string, :required, Section.active.pluck(:url).join(", ")
response :ok
response :not_found
end

About rails expire_page routes

In my Rails4 app I use actionpack-page_caching.
I have a controller like this:
class CodeController < ApplicationController
def home
end
end
and the route:
get "/code/:order/(:page)" => "code#home"
Then when I clear the page caching
expire_page(:controller => 'code', :action => 'home')
I got the error:
No route matches {:action=>"home", :controller=>"code"}
Why? and what should I do?
According to Rails guides
Page Caching has been removed from Rails 4. See the actionpack-page_caching gem. See DHH's key-based cache expiration overview for the newly-preferred method.

In Rails Controller testing, is there a way to pass query (non-routing) parameters?

I'm writing controller tests in Rails and RSpec, and it seems from reading the source code of ActionController::TestCase that it's not possible to pass arbitrary query parameters to the controller -- only routing parameters.
To work around this limitation, I am currently using with_routing:
with_routing do |routes|
# this nonsense is necessary because
# Rails controller testing does not
# pass on query params, only routing params
routes.draw do
get '/users/confirmation/:confirmation_token' => 'user_confirmations#show'
root :to => 'root#index'
end
get :show, 'confirmation_token' => CONFIRMATION_TOKEN
end
As you may be able to guess, I am testing a custom Confirmations controller for Devise. This means I am jacking into an existing API and do not have the option to change how the real mapping in config/routes.rb is done.
Is there a neater way to do this? A supported way for get to pass query parameters?
EDIT: There is something else going on. I created a minimal example in https://github.com/clacke/so_13866283 :
spec/controllers/receive_query_param_controller_spec.rb
describe ReceiveQueryParamController do
describe '#please' do
it 'receives query param, sets #my_param' do
get :please, :my_param => 'test_value'
assigns(:my_param).should eq 'test_value'
end
end
end
app/controllers/receive_query_param_controller.rb
class ReceiveQueryParamController < ApplicationController
def please
#my_param = params[:my_param]
end
end
config/routes.rb
So13866283::Application.routes.draw do
get '/receive_query_param/please' => 'receive_query_param#please'
end
This test passes, so I suppose it is Devise that does something funky with the routing.
EDIT:
Pinned down where in Devise routes are defined, and updated my example app to match it.
So13866283::Application.routes.draw do
resource :receive_query_param, :only => [:show],
:controller => "receive_query_param"
end
... and spec and controller updated accordingly to use #show. The test still passes, i.e. params[:my_param] is populated by get :show, :my_param => 'blah'. So, still a mystery why this does not happen in my real app.
Controller tests don't route. You are unit-testing the controller--routing is outside its scope.
A typical controller spec example tests an action:
describe MyController do
it "is successful" do
get :index
response.status.should == 200
end
end
You set up the test context by passing parameters to get, e.g.:
get :show, :id => 1
You can pass query parameters in that hash.
If you do want to test routing, you can write routing specs, or request (integration) specs.
Are you sure there isn't something else going on? I have a Rails 3.0.x project and am passing parameters.. well.. this is a post.. maybe it's different for get, but that seems odd..
before { post :contact_us, :contact_us => {:email => 'joe#example.com',
:category => 'Category', :subject => 'Subject', :message => 'Message'} }
The above is definitely being used in my controller in the params object.
I am doing this now:
#request.env['QUERY_STRING'] = "confirmation_token=" # otherwise it's ignored
get :show, :confirmation_token => CONFIRMATION_TOKEN
... but it looks hacky.
If someone could show me a neat and official way to do this, I would be delighted. Judging from what I've seen in the source code of #get and everything it calls, there doesn't seem to be any other way, but I'm hoping I overlooked something.

Rails: link_to calls custom method in controller

I am looking to use link_to to call a method in my controller. However, for some odd reason the route looks for the show method.
In my view:
<% #beverages.each do |beverage| %>
..
<%= link_to 'Archive', beverages_archive_path(:id => beverage.id) %>
..
<% end %>
In my config/routes.rb
match 'beverages/archive' => 'beverages#archive'
In my beverages_controller.rb
def archive
beverage = Beverage.find(params[:id])
respond_to do |format|
# format.html # show.html.erb
format.json { render json: beverage }
end
# beverage.update_attribute('archive', true)
end
When I click on the archive link in the view, the URL does change to: http://localhost:3000/beverages/archive?id=11, however I get the following error.
The error I get:
ActiveRecord::RecordNotFound (Couldn't find Beverage with id=archive):
app/controllers/beverages_controller.rb:46:in `show'
Any idea on what I am doing wrong? Your help is much appreciated!
PS. I also looked at Rails 3 link_to delete destory method calls show method?
but nothing seemed to work.
Have you tried this in your routes?
match 'beverages/:id/archive' => 'beverages#archive', as: :beverages_archive
This will create the beverages_archive_path method for you. Also, as you are looking for a specific beverage, use :id inside the route so that it knows where to take the id parameter from.
Apart from that, you can always tell a link specifically which controller and action to link to by doing:
link_to "Label", :controller => :my_controller, :action => :index
Taken from here: Ruby on rails 3 link_to controller and action
Use the other notation (not match) instead.
resources :beverages do
collection do
get :archive
end
end
Try this one out and let me know if something went wrong.
There's not quite enough information here to know why beverages_archive_path works in your app -- one problem is that your routes file does not define a name for your beverages#archive route. What you want is something like:
match 'beverages/archive' => 'beverages#archive', :as => :beverages_archive
or better yet use resourceful routing conventions like so:
resources :beverages do
collection do
get :archive
end
end
What's happening is that you have a beverages#show route that matches /beverages/:id, and this is what /beverages/archive matches (with :id => 'archive').

Resources