简体   繁体   English

Rails-用于多个相同http方法之一的相同路由

[英]Rails - same route for more than one of the same http methods

Is there any way that it's possible for me to have the same URL for multiple actions (in different controllers) where the HTTP method is the same? 对于HTTP方法相同的多个动作(在不同的控制器中),我是否有可能使我拥有相同的URL?

eg 例如

get 'users/:username/profile' => 'users#profile', as: :user_profile
  put 'users/:username/profile' => 'users#avatar_upload', as: :edit_user_avatar
  post 'users/:username/profile' => 'users#update', as: :user_edit_profile
  post 'users/:username/profile' => 'userspayment#create', as: :add_user_payment_details
  post 'users/:username/profile' => 'userspayment#update', as: :user_edit_payment_details

Currently I have: 目前我有:

get 'users/:username/profile' => 'users#profile', as: :user_profile
  put 'users/:username/profile' => 'users#avatar_upload', as: :edit_user_avatar
  post 'users/:username/profile' => 'users#update', as: :user_edit_profile
  post 'users/:username/profile/payment-details/add' => 'userspayment#create', as: :add_user_payment_details
  post 'users/:username/profile/payment-details/edit' => 'userspayment#update', as: :user_edit_payment_details

But when I run the add or update method in userspayment_controller.rb I'm rendering the users/profile view afterwards and the URL changes. 但是,当我在userspayment_controller.rb运行addupdate方法时,我随后将呈现users/profile视图,并且URL会更改。 I don't want to redirect because the add and update forms are in tabs and a redirect will make the first tab active. 我不想重定向,因为添加和更新表单位于选项卡中,并且重定向将使第一个选项卡处于活动状态。 This is my UserpaymentsController : 这是我的UserpaymentsController

class UserspaymentController < ApplicationController
  before_action :authenticate_user!
  before_action :set_user

  def create
    respond_to do |format|
      @user_payment_details = UsersPaymentDetails.new(users_payment_details_params)
      if @user_payment_details.save
        record_activity('Updated payment information.')
        format.html { render :template => "users/profile", :locals => { :user => @user }, notice: 'Payment details was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render(:file => Rails.root.join('public', '422'), :formats => [:html], :status => 422, :layout => false) }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      @user_payment_details = UsersPaymentDetails.find_by(user_id: @user.id)
      if @user_payment_details.update(users_payment_details_params)
        record_activity('Updated payment information.')
        format.html { render :template => "users/profile", :locals => { :user => @user }, notice: 'Payment details was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render(:file => Rails.root.join('public', '422'), :formats => [:html], :status => 422, :layout => false) }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find_by(username: params[:username])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def users_payment_details_params
      params.require(:users_payment_details).permit(:bank, :branch, :code, :account, :holder, :user_id)
    end
end

As the other comment stated, your approach isn't going to work. 正如另一条评论所述,您的方法行不通。 However... 然而...

In your routes.rb , you could do: 在您的routes.rb ,您可以执行以下操作:

resources :users, param: :user_name

scope :users do 
  patch ':user_name/*other', controller: :users, action: :update
  get   ':user_name/*other', controller: :users, action: :show
  post  ':user_name/*other', controller: :users, action: :create
end

Which will give you: 这会给你:

    users GET    /users(.:format)                       users#index
          POST   /users(.:format)                       users#create
 new_user GET    /users/new(.:format)                   users#new
edit_user GET    /users/:user_name/edit(.:format)       users#edit
     user GET    /users/:user_name(.:format)            users#show
          PATCH  /users/:user_name(.:format)            users#update
          PUT    /users/:user_name(.:format)            users#update
          DELETE /users/:user_name(.:format)            users#destroy
          PATCH  /users/:user_name/*other(.:format)     users#update
          GET    /users/:user_name/*other(.:format)     users#show
          POST   /users/:user_name/*other(.:format)     users#create

Now, when you have a url like: 现在,当您使用类似以下的url

/users/foo-bar/profile

it will route to the appropriate update , show , or create action (depending on the HTTP verb) with a params[:other] equal to profile . 它将使用等于profileparams[:other]路由到适当的updateshowcreate动作(取决于HTTP动词)。

In your ApplicationController , you could do something like: 在您的ApplicationController ,您可以执行以下操作:

class ApplicationController < ActionController::Base

  private

    def call_action_service
      action_service.call params.except(:controller, :action, :other)
    end

    def action_service
      "#{params[:controller].camelize}::#{params[:other].gsub('-','_').camelize}::#{params[:action].camelize}Service".constantize
    end

end

So, if you did a get on /users/foo-bar/profile , then action_service would resolve to: 因此,如果您get/users/foo-bar/profile ,那么action_service将解析为:

Users::Profile::ShowService

And you could make your UsersController something like: 您可以使您的UsersController类似:

class UsersController < ApplicationController

    def show
      unless params[:other]
        # do regular show
      else
        call_action_service
      end
    end

    def update
      unless params[:other]
        # do regular update
      else
        call_action_service
      end
    end

    def create
      unless params[:other]
        # do regular create
      else
        call_action_service
      end
    end

  private 

end

You'll note that you have only the RESTful actions, now ( show , update , create , etc.) and have done away with non-RESTful actions (like profile , and avatar_upload ). 您会注意到,您现在只有RESTful动作( showupdatecreate等),并且取消了非RESTful动作(如profileavatar_upload )。

So, in the end, the following HTTP verbs and url s will call the services: 因此,最后,以下HTTP verbsurl将调用服务:

GET    /users/:user_name/profile                    == calls ==>   Users::Profile::ShowService
PATCH  /users/:user_name/profile                    == calls ==>   Users::Profile::UpdateService
PATCH  /users/:user_name/profile/avatar             == calls ==>   Users::Profile::Avatar::UpdateService
PATCH  /users/:user_name/profile/payment-details    == calls ==>   Users::Profile::PaymentDetails::UpdateService
POST   /users/:user_name/profile/payment-details    == calls ==>   Users::Profile::PaymentDetails::CreateService

If we continue with the example of making a get call to /users/foo-bar/profile , then you'll need a Users::Profile::ShowService : 如果继续以对/users/foo-bar/profile进行get调用为例,那么您将需要一个Users::Profile::ShowService

#app/services/users/profile/show_service.rb
module Users
  module Profile
    class ShowService < ServiceBase 

      def call
        # do useful stuff
      end

    end
  end
end    

You'll also need ServiceBase : 您还需要ServiceBase

#app/services/service_base.rb
class ServiceBase

  attr_accessor *%w(
    args
  ).freeze

  class << self 

    def call(args={})
      new(args).call 
    end

  end

  def initialize(args)
    @args = args
  end

  def call
    # this is the fall back `call` method for all services
  end

end

To make generating your paths easier, you might do something like: 为了使生成路径更容易,您可以执行以下操作:

#app/helpers/application_helper.rb
module ApplicationHelper

  def other_user_path(other)
    user_path(@user.name).send(:<<, "/#{other}")
  end

end

So that you could do something like: 这样您可以执行以下操作:

other_user_path('profile/payment-details')

and get 并得到

/users/foo-bar/profile/payment-details

Naturally, you'll want to add back in your respond_to do |format| 自然地,您将需要重新添加回覆以respond_to do |format| stuff. 东西。 But, I'll leave that to you to fiddle with. 但是,我会留给您摆弄。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM