activeadmin singleton resource - ruby-on-rails

i'd like to create settings page via activeadmin (edit/update).
https://github.com/huacnlee/rails-settings-cached.
But i faced that there is no way to register resource (not resources) in routes for particular page, eg have routes like /admin/settings, but not admin/settings/:id
inherit_resource has
defaults singleton: true
for this case, but this doesnt work for activeadmin.
Please help.
Otherwise, i can go with register_pagse way and create form myself and update action,but another problem appeared: how can i render errors messages on form from that update action.
The singleton way is way preferred.

You can always force the index action to redirect to the singleton resource that you want. While this is not a perfect solution, I have used it in the past. Something like this:
ActiveAdmin.register Setting, as: 'Setting' do
actions :all, only: [:show, :edit, :update, :index]
controller do
def index
redirect_to resource_path(Setting.first)
end
end
end

Related

How to share conditional redirect logic for multiple routes in Rails?

I'm using Devise for authentication in a Rails 6 app. Once a user logs in, I'd like to conditionally check that they have completed onboarding before allowing them to visit any and all authenticated routes. If they haven't, then they should be redirected back through the onboarding flow. Something like this:
unless current_user.has_completed_onboarding
redirect_to '/onboarding'
end
I have about a dozen routes where I want to implement this logic. What's the best way to add this check before each request to an authenticated route without duplicating it within each controller? Thanks!
what you can do in this type of case is write a method in the ApplicationController. Suppose check_user_onboarding
def check_user_onboarding
return redirect_to '/onboarding' unless current_user.has_completed_onboarding
end
Then in the controllers you can check by adding a before_action callback. The below one will check all the methods of that controller.
before_action :check_user_onboarding
You can also specify the methods that needs to be checked like -
before_action :check_user_onboarding, only: [:method1, :method2]
or there is also except
before_action :check_user_onboarding, except: [:method1, :method2]

Check if user_signed_in before run the special def in Rails

For example I have defs: def index, def manage, def new. And in routes I have the next:
if user_signed_in?
def new
end
end
But when I wrote it other def(index and manage) also asks me login. How can I do that just new def asks me login?
routes:
get "/new" => "posts#new"
Try adding this line to the controller instead
before_filter :authenticate_user!, only: [:new]
If you are indeed using Devise please skim the guide in its entirety.The filters are what you missed.
before_filter :authenticate_user! is the way to go.
What you are doing in your question is conditionally defining the controller's actions based on a boolean of whether a user is signed in/not, which is, in essence, a wrong approach. Besides, at the point of definition of the controller class, there isn't a user.

Rails route error: NoMethodError

I'm new to Rails, and am trying to create a page that is largely a copy of my users#show page, with slightly different content and formatting. Ideally, this would work something like this:
Normal route: http://myUrl.com/users/2
New route: http://myUrl.com/users/2/lightbox <-this is the new route with the formatting. It should have access to user #2's info.
I did some research on stack overflow, and added the following to routes.rb
resources :users do
member do
get 'lightbox'
end
end
and then raked the routes. This allows me to type in the url http://myUrl.com/users/2/lightbox . However, it doesn't seem to have access to any of the user class's resources, and seems to have no idea who User #2 is.
I may completely have gone about this the wrong way - all I really want to do is create a custom page to display an individual user's information that's different from the show page. I'd really appreciate any help!
You need to add an action to your app/controllers/users_controller.rb:
def lightbox
#user = User.find(params[:id]
# any other logic, look at your show method
end
Routing only maps a url to a controller action. It is up to the controller action, each individually, to set variables and render the view.
Before filters and helper methods are used make sure you don't have to write code a bunch of times. For example:
before_filter :find_user, only: [ :show, :lightbox ]
def show
end
def lightbox
end
protected
def find_user
#user = User.find(params.fetch :id)
end

Rails Variable across all controller actions

This should be a very simple rails question. I have a variable like the following.
#administration = Administration.first
I want this variable to be accessible through every controller action across all my controllers so for example if I have a Product controller and inside of it I have the usual CRUD actions, I want the #administration variable as defined above to be put into all the CRUD actions. (It would not be needed in destroy or create or update). I have many controllers throughout my project and I was wondering if there is an easier way than adding it manually through all of the actions that I want it in.
I tried a global variable
$administration = Administration.first
but I run into an issue where it is not updated when I update the actual content of the Administration.first table. Also, I would like to avoid global variables.
Any help would be much appreciated. Thanks! :)
You could add a before_filter to your ApplicationController that sets the administration variable before any action is called and you can limit it to only the actions you require.
class ApplicationController < ActionController::Base
...
before_filter :set_admin
def set_admin
#administration = Administration.first
end
..
http://api.rubyonrails.org/v2.3.8/classes/ActionController/Filters/ClassMethods.html
Just extending Christos post...
If you don't want #administration to be accessible to destroy, create and update controller actions then add :except => :action to before_filter like this:
before_filter :set_admin, :except => [:create, :update, :destroy]
On Rails 4 and 5 before_filter it's deprecated. You can use this instead:
before_action :set_admin, except: [:create, :update, :destroy]

Single resource and multiple resources

I have a model Whitelabel and a User has_many :whitelables
I have a custom method current_whitelabel (like authlogic or restful_auth for current_user)
I want my users to manage their whitelabels (ie: edit_whitelabels_path(id)).
But I don't want to send the whitelabel ID in params when it refers to the current_whitelabel.
So my idea is to create two resources: map.resources whitelabels and map.resource whitelabel.
But I don't like this so much. Is there any sexier way to accomplish it ?
Ok I finally solved my problem.
Each whitelabel has his own subdomain (thanks to subdomain_fu), so I just need a single resource whitelabel in my routes to do action on my current_whitelabel and if I want to do action on others whitelabels, I just have to switch the subdomain.
Thanks EmFi for trying to answer to my strange question.
In your controller action you can do this:
class WhitelabelsController < ActionController
def edit
#whitelabel = params[:id] ? Whitelabel.find(params[:id]) : current_whitelabel
redirect_to whitelabels_url unless #whitelabel
....
end
...
end
Now rails will treat /whitelabel/edit as /whitelabel/edit/#{current_whitelabel.id} without specifying the id.
If this happens for more than one action you can do it as a before filter. Just be sure to remove all #whitelabel = Whitelable.find(params[:id]) lines from the individual actions.
class WhitelabelsController < ActionController
before_filter :select_whitelabel, :except => [:index, :new]
def select_whitelabel
#whitelabel = params[:id] ? Whitelabel.find(params[:id]) : current_whitelabel
redirect_to whitelabels_url unless #whitelabel
end
...
end
Answering the more clearly stated question in the comment:
You can use a singular resource in tandem with the above code to have the effect you want.
config/routes.rb
map.resource :my_whitelabel, :controller => "whitelabels", :member => {:dashboard => :get}
Then in the whitelabels controller use the above code. This keeps things DRY by using the same controller for different paths with the same actions. The resource defines a dashboard action, so you'll have to add that to the controller too. But if you're using the before_filter version there should be no problem.

Resources