首页 > 解决方案 > 重构讨厌的 Rails 控制器

问题描述

我一直在向控制器添加一些“盲目”的东西,目前一切正常,但控制器变得非常混乱。我正在使用 gemrails_best_practices来整理我的代码,但除了将一些方法从控制器移动到模型之外,它目前没有给我任何其他修复。

几个问题

是否有其他类似rails_best_practices的宝石可以用来弄清楚如何整理控制器?

其次

关于我应该在这里做什么样的改变有什么建议吗?

我在这里做一些授权,我认为我应该使用 gem 来处理,但目前没有使用任何授权 gem。

这是混乱

class OffersController < ApplicationController
  before_action :authenticate_user!
  before_action :offer_authorised, only: [:show]
  before_action :set_offer, only: [:accept, :reject, :send_signature_requests, :make_payment]
  before_action :is_authorised, only: [:accept, :reject]

  def create
    session[:return_to] ||= request.referer
    if !current_user.stripe_id?
      return redirect_to payment_path, alert: "Connect your bank accout before payments."
    end
    rental = Rental.find(offer_params[:rental_id])

    if rental && rental.user_id == current_user.id
      redirect_to(request.referrer, alert: "You cannot make an offer from your own property.") && return
    end

    if current_user.offers.accepted.any?
      redirect_to(request.referrer, alert: "You've already rented an apartment.") && return
    end

    if Offer.exists?(user_id: current_user.id, rental_id: offer_params[:rental_id])
      redirect_to(request.referrer, alert: "You can only make one offer at a time.") && return
    end

    @offer = current_user.offers.build(offer_params)
    @offer.landlord_id = rental.user.id
    if @offer.save
      redirect_to applications_path, notice: "Offer sent."
    else
      redirect_to request.referrer, flash: {error: @offer.errors.full_messages.join(", ")}
    end
  end

  def destroy
    @offer = Offer.find(params[:id])
    @offer.destroy
    redirect_to request.referrer, notice: "Offer deleted."
  end

  def accept
    if @offer.waiting?
      @offer.accepted!
      @offer.rental.update(active: !@offer.rental.active?)
      Offer.where(landlord_id: current_user.id, rental_id: @offer.rental.id).where.not(id: @offer.id).update_all(status: 2)
      @offer.rental.tours.destroy_all
      @offer.user.tours.destroy_all
      OfferMailer.with(offer: @offer, tenant: @offer.user_id, landlord: @offer.landlord_id).offer_accepted.deliver_now
      flash[:notice] = "Offer accepted."
    end
    redirect_to offer_accepted_path(@offer)
  end

  def reject
    if @offer.waiting?
      @offer.rejected!
      flash[:notice] = "Offer rejected."
    end
    redirect_to request.referrer
  end

  def update
    @offer = Offer.find(params[:id])
    if params[:offer][:due_date]
      @offer.update(due_date: params[:offer][:due_date])
    end
    if params[:offer][:rental_agreement]
      @offer.rental_agreement.purge
      @offer.rental_agreement.attach(params[:offer][:rental_agreement])
    end
    flash[:notice] = "Saved."
    redirect_to request.referrer
  end

  def show
    @offer = Offer.find(params[:id])
    @rental = @offer.rental_id ? Rental.find(@offer.rental_id) : nil
    @comments = Comment.where(offer_id: params[:id])
    @has_attachment_file_sent = Comment.where(user_id: @offer.landlord_id).any? { |obj| obj.attachment_file.attached? }
    respond_to do |format|
      format.html
      format.js { render layout: false }
    end
  end

  def pay_rent
    @offer = Offer.find(params[:id])
    @rental = @offer.rental_id ? Rental.find(@offer.rental_id) : nil
    if @rental.user_referral_reward_count > 0
      referral_rent_payment(@rental, @offer)
    else
      make_payment(@rental, @offer)
    end
    flash[:notice] = "Payment succeeded."
    redirect_to request.referrer
  end

  def send_signature_requests
    landlord_mail = User.where(id: @offer.landlord_id)[0].email
    tenant_mail = User.where(id: @offer.user_id)[0].email
    if  @offer.rental_agreement.attached?
      attachment_file = @offer.rental_agreement
      blob_path = rails_blob_path(attachment_file, disposition: "attachment", only_path: true)
      response = HTTParty.get("URL", body: {
        landlord_mail: landlord_mail,
        tenant_mail: tenant_mail,
        agreement_url: blob_path
      }.to_json,
      headers: {"Content-Type" => "application/json"})
      @offer.update(invitation_uuid: response.parsed_response["invitation_uuid"], document_uuid: response.parsed_response["document_uuid"])
      flash[:notice] = "Signature requests sent."
      redirect_to request.referrer
    else
      flash[:alert] = "Add aggreement."
      redirect_to request.referrer
    end
  rescue => e
    flash[:alert] = "Failed to send signature requests."
    redirect_to request.referrer
  end

  private

  def make_payment(rental, offer)
    unless offer.user_stripe_id.blank?
      payment_methods = Stripe::PaymentMethod.list(
        customer: offer.user_stripe_id,
        type: "sepa_debit"
      )
      payment_intent = Stripe::PaymentIntent.create({
        payment_method_types: ["sepa_debit"],
        payment_method: payment_methods.data[0].id,
        confirm: true,
        off_session: true,
        customer: offer.user_stripe_id,
        amount: offer.amount * 100,
        currency: "eur",
        application_fee_amount: offer.amount * 4,
        metadata: {"name" => User.where(id: offer.user_id).first.full_name, "offer" => offer.id},
        transfer_data: {
          destination: rental.user_merchant_id
        }
      })
    end
  rescue Stripe::CardError => e
    flash[:alert] = e.message
  end

  def referral_rent_payment(rental, offer)
    unless offer.user_stripe_id.blank?
      referrer = User.find_by(id: rental.user.id)
      customer = Stripe::Customer.retrieve(offer.user_stripe_id)
      charge = Stripe::Charge.create(
        customer: customer.id,
        amount: offer.amount * 100,
        description: "Rent for #{rental.listing_name}",
        currency: "eur",
        application_fee_amount: offer.amount * 2,
        metadata: {"name" => User.where(id: offer.user_id).first.full_name, "offer" => offer.id},
        transfer_data: {
          destination: rental.user_merchant_id
        }
      )
      referrer.update_attribute(:referral_reward_count, referrer.referral_reward_count -= 1)
    end
  rescue Stripe::CardError => e
    flash[:alert] = e.message
  end

  def offer_authorised
    unless Offer.exists?(["id = ? AND (landlord_id = ? OR user_id = ?) AND status = ?", params[:id], current_user.id, current_user.id, 1])
      redirect_to dashboard_path,
        alert: "You're not authorized."
    end
  end

  def set_offer
    @offer = Offer.find(params[:id])
  end

  def is_authorised
    redirect_to root_path, alert: "You're not authorized." unless current_user.id == @offer.rental.user_id
  end

  def offer_params
    params.require(:offer).permit(:amount, :rental_id, :status, :priority, :rental_agreement)
  end
end

标签: ruby-on-railsrubyrefactoring

解决方案


那么你可以试试reek gem 它有助于检测代码中的气味。


推荐阅读