Using Administrate gem, how to render edit page via custom update action? - ruby-on-rails

I'm trying to have my custom update action for my user controller render the edit page if they fail to validate, like so:
def update
user = User.find(params[:id])
user.update(user_params)
# zero because checkbox
user_params[:banned] == "0" ? user.remove_role(:banned) : user.add_role(:banned)
if user.banned_note
if user.banned_note.update(content: params[:user][:reason_for_ban])
redirect_to "/admin/users/#{params[:id]}"
else
render "edit.html.erb" # this line
end
end
end
def find_resource(param)
User.find!(id: param)
end
I want to render the edit page with a flash message listing the errors, but what I have doesn't work. I'm not sure how to route to the correct action, since there's no actual view or edit action (which are auto generated by the Administrate gem).

Pandy, I have not used this gem but looking the source code and this comment of this issue in GitHub, Have you try the following?
def update
user = User.find(params[:id])
user.update(user_params)
# zero because checkbox
user_params[:banned] == "0" ? user.remove_role(:banned) : user.add_role(:banned)
if user.banned_note
if user.banned_note.update(content: params[:user][:reason_for_ban])
redirect_to "/admin/users/#{params[:id]}"
else
#This two lines
flash.now[:notice] = "Something"
render :new, locals: {
page: Administrate::Page::Form.new(dashboard, resource),
}
end
end
end
def find_resource(param)
User.find!(id: param)
end

Related

rails 5 redirect_back not working

i have a admin edit page and form in here. when i submit the form, it is going to the update action and updates the admin, there is no problem. After the update, i want redirect to the index page in the same controller. But it gets redirected to the edit form again. I tried a couple of things but in vain and gets redirected to edit page. i tried too much things but it is always going to edit page.
Controller (admins_controller.rb)
class Admin::AdminsController < ApplicationController
def index
#admins = Admin.all
end
def edit
#admin = Admin.find(params[:id])
end
def update
#admin = Admin.find(params[:id])
if #admin.update(admin_params)
redirect_back fallback_location: admin_admins_path
else
render 'edit'
end
end
private
def admin_params
params.require(:admin).permit(:id, :username, :password)
end
end
I'm trying admin_admins_path it does not work.
redirect_back like its name, it redirects to the route which it submitted the request, in this case is the edit page.
you should use redirect_to
redirect_to admin_index_path

Rails4: losing form validation errors while using `redirect_to` in controller

I've been trying to fix this for a while but haven't gotten anywhere yet. Would appreciate if someone could let me know how how this can be done, or if there is any way i can use the render method to do this instead (currently preserves errors but redirects to wrong path as mentioned below...)
I have a custom route for form which I am trying to redirect back when there are validation errors:
get "clubs/sign_up/:plan_id", to: "clubs#new", as: :new_membership
below is what I have so far in my controller along along with some comments regarding other steps I have tried
clubs_controller.rb
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = "Please check form errors:"
redirect_to new_membership_path(session[:membership_plan_id]) #errors lost
# render action: 'new', plan_id: 'silver' # <<<Preserves errors but breaks path, renders: localhost:3000/clubs instead of .../clubs/sign_up/:plan_id
# session[:membership_errors] = #membership.errors #<<< Doesn't wotk either, getting a cookie overflow error when trying to pass errors to #new
return
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new
end
Assuming plan_I'd is part of your model..
Change your render line to:
render :new
Change the rest to:
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new plan_id: params[:plan_id]
end
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = #membership.errors.full_messages.to_sentence
render :new
end
end
And add a hidden field for plan_id in your form. The reason render goes wrong is that it does not have the param available, trying to add it to the render operation does not work hence your issue
You need to render instead of redirecting. Use the ||= operator to help here.. It's all just ruby, so something like
(..snip..)
else
flash[:error] = "Problem with form"
new
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership ||= Membership.new
render 'new'
end

Conditional routing for nested resource in Rails controller #edit action, depending on where request came from

I have a Foo resource that has_many Bars. I'm using nested resources for a limited number of actions, but otherwise prefer to keep my routing for bars shallow. There are two ways to navigate to the edit view for the Bar object - either from the nested path that includes foo, or from the shallower bar path that isn't nested inside foo. For example, a user might click the edit button from the page at /foos/[:foo_id]/bar/[:bar_id]; or from /bars/[:bar_id].
In the first case, I want the controller to redirect the user back to the parent foo page: /foos/[:foo_id] after the record is updated. In the second case, I want it to redirect to the index view for bars: /bars. I believe I need some sort of conditional in the #edit action in the bars controller that will tell Rails where to go after #update executes.
# config/routes.rb
resources :foos do
resources :bars, only: [:new, :edit]
end
resources :bars
# bin/rake routes:
foo_bars POST /foos/:foo_id/bars(.:format) bars#create
new_foo_bar GET /foos/:foo_id/bars/new(.:format) bars#new
edit_foo_bar GET /foos/:foo_id/bars/:id/edit(.:format) bars#edit
bars GET /bars(.:format) bars#index
POST /bars(.:format) bars#create
new_bar GET /bars/new(.:format) bars#new
edit_bar GET /bars/:id/edit(.:format) bars#edit
bar GET /bars/:id(.:format) bars#show
PATCH /bars/:id(.:format) bars#update
PUT /bars/:id(.:format) bars#update
DELETE /bars/:id(.:format) bars#destroy
The controller for bars:
# app/controllers/bar_controller.rb
def edit
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
#bar = bar.find(params[:id])
#foo = #bar.foo
respond_to do |format|
if #bar.update_attributes(bar_params)
format.html { redirect_to #foo, notice: "bar successfully updated" }
else
format.html { render action: "edit" }
end
end
end
I'm trying to change the redirect_to #foo line in the #update action so there is conditional logic that switches out #foo for #bars depending on where the #edit action was initiated. I've tried something like the following to test whether params[:foo] is present when the #edit action is called, setting an instance variable for the redirect.
def edit
if params[:foo]
#redirect_page = #foo
else
#redirect_page = #bars
end
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
# code omitted...
format.html { redirect_to #redirect_page, notice: "bar successfully updated" }
# code omitted...
end
This doesn't work. Rails states cannot redirect to nil!. I've also tried something using a test based on URI(request.referer).path in the #edit action, without success.
I'm still not entirely clear how the Rails magic happens in the controller. I believe the #edit action is the proper place to define the conditional for the redirect (or through a method called in the #edit action), as that's where the controller will "see" the incoming request and know where it came from. But I can't quite figure out to capture that information, and pass it along to #update. Appreciate any guidance.
In your edit forms, add a hidden_field_tag:
<%= hidden_field_tag "route", request.env['PATH_INFO'] %>
Then in your controller, you can have an if statement and use a redirect_to based on what the params[:route] is.
I figured it out. The params[:route] method using request.env['PATH_INFO] wasn't working for me, because the 'PATH_INFO' variable in the form was providing the path handed off to the bars#update action, instead of the path where the bars#edit action was initiated.
After clicking "Edit" from the parent foo page at /foos/[:id] the params hash is:
>> params
=> {"controller"=>"bars", "action"=>"edit", "foo_id"=>"3786", "id"=>"16"}
There is no value for params[:route] when the form is first accessed - the hidden field is only added to the params hash after clicking "Update" in the edit form:
>> params[:route]
=> "/foos/3786/bars/16/edit"
This could work, but would require building logic to parse the route in order to redirect to /foos/[:foo_id]
It turned out to be simpler to use the Rails flash method to store the path for redirecting back to the source page. I did this by calling a custom method set_redirect_path in the BarsController, and calling it in bars#edit. This sets a value for the source in the flash, which is available in bars#update. Maybe there's a better/more conventional way to achieve this, but this seems to be a clean and simple way to do what I want.
# app/controllers/bars_controller.rb
def edit
set_redirect_path
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
#bar = bar.find(params[:id])
#foo = #bar.foo
respond_to do |format|
if #bar.update_attributes(bar_params)
format.html { redirect_to flash[:source], notice: "bar successfully updated" }
format.xml { head :ok }
else
format.html { render action: "edit" }
format.xml { render xml: #bar.errors, status: :unprocessable_entity }
end
end
end
private
def set_redirect_path
flash[:source] = URI(request.referer).path
end
One advantage of this approach is I can now get rid of conditional logic in the shared partial app/views/bars/_list.html.haml that was required to determine whether clicking the "Edit" button should route to edit_foo_bar_path or to edit_bar_path (i.e. the former is chosen if #foo exists). Consequently, I can delete :edit for the nested resource :bars. Since the flash captures the incoming source of the request and stores it for reference in the #update action, all edit requests can use the same edit_bar_path, regardless of where they originate from. After update Rails redirects the user to the point where they initiated the #edit action.

Can't overwrite the active admin default redirect path

I am using active admin in my application. In my controller, I have an action update with redirect_to function. But while updating, it threw me an error.
Render and/or redirect were called multiple times in this action. Please note that you may only call render or redirect, and at most once per action. Also note that neither redirect nor render terminates execution of the action, so if you want to exit an action after redirecting, you need to do something like redirect_to(...) and return.
def update
#user = User.find(params[:id])
#user.update
mailers.notify(#user).deliver
redirect_to user_path(#user)
end
I tried
only redirect_to
redirect_to() and return
but nothing works.
before_filter :only =>[:create,:update] do
if self.action_name.to_sym == :create
#user = User.new(params[:user])
else
#user = User.find(params[:id])
end
I fix it by adding this to my update action .This works for me fine.
def update
update!do |format|
format.html { redirect_to_user_path(#user)}
end
What is your purpose? Why you use mailers.notify(#user).deliver inside the update action?
Move the notification to after_update filter in your User model, smth like this:
after_update :send_notifications
def send_notifications
Mailer.notify(self).deliver
end
Change the update method to smth like this:
def update
super do |format|
redirect_to user_path(#user), notice: "Your notice message" and return if resource.valid?
end
end

Rails update_attributes always redirects

I'm writing a edit page for a record in my database, I want to redirect if the update was successful and render the edit page again for any errors. Here is the code:
def edit
#list = List.find(params[:id])
if #list.update_attributes(params[:list])
redirect_to(root_path)
else
render('edit')
end
end
The redirect fires as soon as I launch the edit page, before any changes are made or the submit button is clicked.
Any ideas greatly appreciated.
Your edit action should look like this:
def edit
#list = List.find(params[:id])
end
It renders the edit view. The form should point (and probably is) to the update action that should look like so:
def update
#list = List.find(params[:id])
if #list.update_attributes(params[:list])
redirect_to(root_path)
else
render :edit
end
end

Resources