How do I redirect after_sign_up_path_for to a create action of another controller?

不羁岁月 提交于 2020-02-06 07:54:10

问题


So I have OrdersController#Create, that I would like the user to be redirected to right after they register (so it can do some post-registration stuff).

Before I implemented the registration part of this workflow, this is what the link_to for that resource looked like:

<%= link_to 'Submit to Scheduling', orders_path(cart_id: @cart), method: :post, data: { confirm: "Are you sure?" }, class: "primary button btn" %>

So basically, I would like to achieve the above functionality (including passing the @cart object as a param), but automatically from within the Devise::RegistrationsController#Create.

I am using Devise, and so I have created a /users/registrations_controller.rb and in that controller I am doing this:

  def after_sign_up_path_for(resource)
    orders_path(cart_id: @cart)
    super(resource)
  end

When I did the above, it successfully created the user and redirected me to Orders#Index which is not what I want, see the logs below:

 User Create (1.3ms)  INSERT INTO "users" ("email", "encrypted_password", "first_name", "last_name", "created_at", "updated_at", "company_name", "company_title", "phone") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["email", "abc3@test.com"], ["encrypted_password", "$2a$11$ZC2X2vCXd5JwVO"], ["first_name", "Test"], ["last_name", "User 3"], ["created_at", "2020-01-22 06:16:11.358863"], ["updated_at", "2020-01-22 06:16:11.358863"], ["company_name", "Acme Inc"], ["company_title", "CFO"], ["phone", "9876543210"]]
  ↳ app/controllers/users/registrations_controller.rb:14:in `create'
   (0.6ms)  COMMIT
  ↳ app/controllers/users/registrations_controller.rb:14:in `create'
Redirected to http://localhost:3000/orders
Completed 302 Found in 162ms (ActiveRecord: 5.3ms | Allocations: 6383)


Started GET "/orders" for ::1 at 2020-01-22 01:16:11 -0500
Processing by OrdersController#index as HTML

I even tried orders_path(cart_id: @cart, method: :post) and that didn't work.

How do I achieve what I am trying to do?

Edit 1

So I discovered url_for and it ALMOST gets me there, but doesn't quite work.

This is what I have:

url_for(controller: '/orders', action: 'create', method: :post, cart_id: @cart.id, only_path: true)

This is what happens:

↳ app/controllers/users/registrations_controller.rb:14:in `create'
  User Create (5.5ms)  INSERT INTO "users" ("email", "encrypted_password", "first_name", "last_name", "created_at", "updated_at", "company_name", "company_title", "phone") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["email", "abc2@test.com"], ["encrypted_password", "$2a$ezj6"], ["first_name", "Test"], ["last_name", "User 2"], ["created_at", "2020-01-22 07:26:09.589560"], ["updated_at", "2020-01-22 07:26:09.589560"], ["company_name", "Acme Inc"], ["company_title", "CEO"], ["phone", "9876543210"]]
  ↳ app/controllers/users/registrations_controller.rb:14:in `create'
   (1.1ms)  COMMIT
  ↳ app/controllers/users/registrations_controller.rb:14:in `create'
/.rvm/gems/ruby-2.7.0@myapp/gems/devise-4.7.1/app/controllers/devise_controller.rb:187: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
.rvm/gems/ruby-2.7.0@myapp/gems/i18n-1.8.1/lib/i18n.rb:195: warning: The called method `t' is defined here
Redirected to http://localhost:3000/orders?cart_id=10&method=post
Completed 302 Found in 307ms (ActiveRecord: 13.2ms | Allocations: 8600)


Started GET "/orders?cart_id=10&method=post" for ::1 at 2020-01-22 02:26:09 -0500
Processing by OrdersController#index as HTML

So it still doesn't work. It is still sending me to OrdersController#Index.


回答1:


You don't need super(resource).

In my understanding, you want to redirect to orders_path(cart_id: @cart) with post method. It's so weird. after_sign_up_path_for should return a some_path, which accessed by get method.

You can try another way, perform another action from another controller. I think this will helpful to you.




回答2:


  request.params.merge!(cart_id: @cart.id)
  controller_you_want = OrdersController.new
  controller_you_want.request = request
  controller_you_want.response = response
  controller_you_want.create

Did you try this ?




回答3:


The problem you have is that your code is returning the original value of the method, not the new path:

def after_sign_up_path_for(resource)
  orders_path(cart_id: @cart)
  super(resource)
end

Returns the overridden method, since you are calling super(resource) as the final expression in the method, and its result gets returned by your defined method.

If it is necessary to call super at all, because the overridden method does something more than just return a string, then either return the order of the calls, or return the value of orders_path with a variable.

def after_sign_up_path_for(resource)
  res = orders_path(cart_id: @cart)
  super(resource)
  res
end

You should check the method being called by super though, as it is possible you can just remove this completely.

Without seeing the rest of your code it is impossible to say whether @cart actually has a value, or is in fact just nil. You should check that it has been set in the controller prior to the after_sign_up_path_for method being called.




回答4:


You could use Devise::Controllers::StoreLocation#store_location_for which is used to redirect back after signing in.

store_location_for(current_user, new_order_path(cart_id: @cart))

This stores the location is the session. You can fetch the value with stored_location_for.

def after_sign_up_path_for(resource)
  stored_location_for(resource) || super
end

However you can't/should not redirect to the create action. Create responds to POST requests. Redirects are always GET requests. Before you go adding a GET /posts/create route remember that GET should not be used for non-idempotent actions. Meaning that a GET request should not create or alter any resources.

If you break this rule your users could have a really bad day when they hit the back button.

And no you don't want to store and repeat the post action. Have the user submit the form - save the record and then redirect. Add a flag to the record if needed to mark it as "not finshed". Redirect the user back to the edit action and then "finish the order" by performing a PUT or PATCH request (update).



来源:https://stackoverflow.com/questions/59853763/how-do-i-redirect-after-sign-up-path-for-to-a-create-action-of-another-controlle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!