Active admin error on Rails 4.0.2 application - ruby-on-rails

Got this error while installing active admin on rails 4.0.2 application. I am using rails-api, where I need something like this admin to manage content apart from client.
undefined method `layout' for ActiveAdmin::Devise::SessionsController:Class
I am not sure about this error.

Okay looks like it has been solved by adding this on application controller.
include AbstractController::Layouts

It is now ActionView::Layouts
See https://github.com/rails/rails/issues/14517

When use rails-api(it's merged into rails 5 now), your ApplicationController will inherits from ActionController::API instead of ActionController::Base, while rails admin dependents on ActionController::Base and some other middlewares. To make active admin works with rails api mode, your need to do some additional work:
Make your ApplicationController inherit from ActionController::Base
class ApplicationController < ActionController::Base
Modify your config/application.rb like this
class Application < Rails::Application
# ...
config.middleware.use ActionDispatch::Flash
config.middleware.use Rack::MethodOverride
config.middleware.use ActionDispatch::Cookies
end
References:
1. https://rrott.com/blog/ror/rails-5-api-with-activeadmin-integration.html
2. What is the difference between a regular Rails app and a Rails API?

Related

Rails 6.0 is still rendering views even with API only mode enabled

Does anyone know how to stop rails from rendering devise login views while using config.api_only = true?
I have this in my application.rb file:
class Application < Rails::Application
config.load_defaults 6.0
config.filter_parameters += [:server_key]
config.api_only = true
Those views are rendered through the controller with YourController < ActionController::Base extended to it, this config.api_only only works on newly generated controllers with YourController < ActionController::API,
check ur application controller if it has ActionController::Base to it, if so change the 'Base' to API to rectify the error.
This link might be useful https://github.com/heartcombo/devise/wiki/API-Mode-Compatibility-Guide
According to this the above link, "Devise.parent_controller extends from ActionController::API (and not ActionController::Base)."
Have you tried this?

How can I extend my controller from installed Spree gem's controller?

I have spree gem installed successfully. I don't need spree_frontend. Here is the Gemfile
gem 'spree_core', '4.2.0.rc2'
gem 'spree_backend', '4.2.0.rc2'
gem 'spree_sample', '4.2.0.rc2'
gem 'spree_cmd', '4.2.0.rc2'
gem 'spree_auth_devise', '~> 4.2'
So I want to extend my ApplicationController from Spree's BaseController. Here is the code:
class ApplicationController < Spree::BaseController
include Spree::Core::ControllerHelpers::Order
end
But I get following errors:
uninitialized constant Spree::BaseController (NameError)
How can I extend my controller from installed Spree gem's controller?
The problem you're running into is that Spree::BaseController already inherits from ApplicationController; see https://github.com/spree/spree/blob/master/core/app/controllers/spree/base_controller.rb. This is to allow your ApplicationController to define things like current_user and similar basic functions before Spree sees it.
Declaring them the other way around as well creates a circular dependency, and the class loading fails as a result. Without changing Spree itself, the only fix is to do something else.
Instead, to have your controllers use Spree::BaseController as a superclass, first define ApplicationController in the more usual fashion e.g.:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# ...
end
then invent a new abstract controller, for your own use, that inherits from Spree, e.g. let's name it StoreBaseController:
# app/controllers/store_base_controller.rb
class StoreBaseController < Spree::BaseController
include Spree::Core::ControllerHelpers::Order
# ...
end
This StoreBaseController can now be used in place of ApplicationController when defining more specific controllers. It works because it doesn't create a loop in the inheritance tree, which now looks like this:
Note: if you're also using the rails generator command to produce controllers or scaffolds from templates, be aware that the generator has ApplicationController hard-coded in the templates, so you'll need to amend them once created.
Is there any reason why you need to extend strictly ApplicationController?
I advise you alternative approach to create a new Base controller class, and then inherit all the children from it and leave ApplicationController to basic rails
app/controller/my_base_controller.rb
class MyBaseController < Spree::BaseController
def foo
# ...
end
end
app/controller/my_resources_controller.rb
class MyResourcesController < MyBaseController
def bar
# ...
end
end
As the errors states, Spree::BaseController is not defined within your app - it is defined in the spree-core gem. If you re-create the filepath to the base controller locally, that is app/controllers/spree/, and copy and paste the code from the controller into a local base_controller.rb, you can edit it and add custom functionality.
Note that it will still inherit from the ApplicationController, but you can place any of the code you wanted to put in the ApplicationController into here and have your classes inherit from Spree::BaseContoller and the effect will be the same.
hmmm, I tried what you want to do but I succeeded (?)
class PagesController < Spree::BaseController
include Spree::Core::ControllerHelpers::Order
end
in the console
2.6.5 :006 > pp PagesController.ancestors
[PagesController,
Spree::Core::ControllerHelpers::Order,
#<Module:0x00007fca27610410>,
Spree::BaseController,
Spree::Core::ControllerHelpers::CurrencyHelpers,
Spree::Core::ControllerHelpers::StrongParameters,
...
I'm using
ruby 2.6.5
rails 6.0.3.4
run bundle update after adding the your spree's gems in the Gemfile
So I think its the requiring or auto-loading problem
what's your rails version? 6? spree >= 4.1 should use rails >= 6
Does Spree::BaseController exist in rails console?
Is Bundler.require(*Rails.groups) in config/application.rb?
Does the gems included in the right group of the Gemfile? ex: spree gems are in :production group.
Does it have config.load_defaults 6.0 in config/application.rb?

Rails: How to implement protect_from_forgery in Rails API mode

I have a Rails 5 API app (ApplicationController < ActionController::API). The need came up to add a simple GUI form for one endpoint of this API.
Initially, I was getting ActionView::Template::Error undefined method protect_against_forgery? when I tried to render the form. I added include ActionController::RequestForgeryProtection and protect_from_forgery with:exception to that endpoint. Which solved that issue as expected.
However, when I try to submit this form I get: 422 Unprocessable Entity ActionController::InvalidAuthenticityToken. I've added <%= csrf_meta_tags %> and verified that meta: csrf-param and meta: csrf-token are present in my headers, and that authenticity_token is present in my form. (The tokens themselves are different from each other.)
I've tried, protect_from_forgery prepend: true, with:exception, no effect. I can "fix" this issue by commenting out: protect_from_forgery with:exception. But my understanding is that that is turning off CSRF protection on my form. (I want CSRF protection.)
What am I missing?
UPDATE:
To try to make this clear, 99% of this app is a pure JSON RESTful API. The need came up to add one HTML view and form to this app. So for one Controller I want to enable full CSRF protection. The rest of the app doesn't need CSRF and can remain unchanged.
UPDATE 2:
I just compared the page source of this app's HTML form and Header with another conventional Rails 5 app I wrote. The authenticity_token in the Header and the authenticity_token in the form are the same. In the API app I'm having the problem with, they're different. Maybe that's something?
UPDATE 3:
Ok, I don't the the mismatch is the issue. However, in further comparisons between the working and non-working apps I noticed that there's nothing in Network > Cookies. I see a bunch of things like _my_app-session in the cookies of the working app.
Here's what the issue was: Rails 5, when in API mode, logically doesn't include the Cookie middleware. Without it, there's no Session key stored in a Cookie to be used when validating the token I passed with my form.
Somewhat confusingly, changing things in config/initializers/session_store.rb had no effect.
I eventually found the answer to that problem here: Adding cookie session store back to Rails API app, which led me here: https://github.com/rails/rails/pull/28009/files which mentioned exactly the lines I needed to add to application.rb to get working Cookies back:
config.session_store :cookie_store, key: "_YOUR_APP_session_#{Rails.env}"
config.middleware.use ActionDispatch::Cookies # Required for all session management
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
Those three lines coupled with:
class FooController < ApplicationController
include ActionController::RequestForgeryProtection
protect_from_forgery with: :exception, unless: -> { request.format.json? }
...
And of course a form generated through the proper helpers:
form_tag(FOO_CREATE_path, method: :post)
...
Got me a CSRF protected form in the middle of my Rails API app.
If you're using Rails 5 API mode, you do not use protect_from_forgery or include <%= csrf_meta_tags %> in any view since your API is 'stateless'. If you were going to use full Rails (not API mode) while ALSO using it as a REST API for other apps/clients, then you could do something like this:
protect_from_forgery unless: -> { request.format.json? }
So that protect_from_forgery would be called when appropriate. But I see ActionController::API in your code so it appears you're using API mode in which case you'd remove the method from your application controller altogether
I had this challenge when working on a Rails 6 API only application.
Here's how I solved it:
First, include this in your app/controllers/application_controller.rb file:
class ApplicationController < ActionController::API
include ActionController::RequestForgeryProtection
end
Note: This was added because protect_from_forgery is a class method included in ActionController::RequestForgeryProtection which is not available when working with Rails in API mode.
Next, add the cross-site request forgery protection:
class ApplicationController < ActionController::API
include ActionController::RequestForgeryProtection
protect_from_forgery with: :null_session
end
OR this if you want to protect_from_forgery conditionally based on the request format:
class ApplicationController < ActionController::API
include ActionController::RequestForgeryProtection
protect_from_forgery with: :exception if proc { |c| c.request.format != 'application/json' }
protect_from_forgery with: :null_session if proc { |c| c.request.format == 'application/json' }
end
Finally, add the line below to your config/application.rb file. Add it inside the class Application < Rails::Application class, just at the bottom:
config.middleware.use ActionDispatch::Flash
So it will look like this:
module MyApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.1
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
# Only loads a smaller set of middleware suitable for API only apps.
# Middleware like session, flash, cookies can be added back manually.
# Skip views, helpers and assets when generating a new resource.
config.api_only = true
config.middleware.use ActionDispatch::Flash
end
end
Note: This will prevent the error below:
NoMethodError (undefined method `flash=' for #<ActionDispatch::Request:0x0000558a06b619e0>):
That's all.
I hope this helps
No need of protect_from_forgery for AJAX calls and apis.
If you want to disable it for some action then
protect_from_forgery except: ['action_name']
class Api::ApiController < ApplicationController
skip_before_action :verify_authenticity_token
end
Use as above with rails 5

`circular dependency` - inheritance in application controller of Rails 4.2.0 engine

When upgrading engine from Rails 3.2 to Rails 4.2.0, the following inheritance in application controller causes circular dependency error in rspec:
class ApplicationController < ApplicationController
end
We have config.eager_load = false for config/development.rb.
The error:
activesupport-4.2.0/lib/active_support/dependencies.rb:492:in `load_missing_constant': Circular dependency detected while autoloading con
stant Authentify::ApplicationController (RuntimeError)
Here is the Rails engine document (ch:4.3.2) explaining this type of code practice. As I understand, the purpose of this inheritance is to allow the engine to access methods in Rails app or other engine which the current engine is mounted to. We would like to do the same in Rails 4.2.0 engine. How to fix this problem?
your applicationController is clearly trying to inherit from itself, it should rather look like
class ApplicationController < ActionController::Base
In rails 4 engine, the right format is:
class ApplicationController < ::ApplicationController
end
assume the class is within module MyEngine. Or
class MyEngineName::ApplicationController < ::ApplicationController
end

How do I reference Rails in a gem I'm making?

I'm making a gem for Rails. I need access to the ApplicationController because I'll toy with it. Absolutely nothing online gives information about what to do with gemspec and then somehow manage to get Rails accessible in my gem.
I imagine the goal is eventually to be able to talk to Rails like:
module Rails
module ActionController
#code
end
end
If you are developing a gem exclusively for Rails I strongly recommend you generate the initial scaffold using rails plugin new gem_name. There's a ton of info on developing rails plugins.
The initial structure generated looks like this:
gem_name
gem_name.gemspec
lib/
gem_name.rb
gem_name/
version.rb
engine.rb # if generated using --mountable
The whole rails environment becomes available [edit: after your gem is loaded] so extending ApplicationController can be done like this:
# lib/gem_name.rb
require 'gem_name/controller_extensions'
module GemName
end
# lib/gem_name/controller_extensions.rb
module GemName::ControllerExtensions
# bleh
end
# dummy_application/app/application_controller.rb
class ApplicationController < ActionController::Base
include GemName::ControllerExtensions
end
Look at this question.

Resources