2016-05-03 13 views
0

Ich habe eine Rails App mit zwei Controllern, die sehr ähnliche Verhaltensweisen haben. Ein ist ein Userscontroller auf das Konzept von Hotel bezogen, der andere ist auch Userscontroller genannt, aber auf das Konzept der Vereinigung im Zusammenhang, so dass es in einem Ordner Verein gespeichert: class Api::V1::Association::UsersController < Api::V1::BaseControllerVerwenden Vererbung für sehr ähnliche Controller in Schienen App

Diese Controller haben sehr ähnliche Verhaltensweisen, Verfahren mit geringfügigem Unterschiede (sie beruhen auf verschiedenen Datenbanktabellen für bestimmte Variablen ...). Ich las über Vererbung und dachte, dass es interessant sein könnte, die Association::UsersController von der UsersController zu erben. Denkst du, das könnte in meinem Fall das Richtige sein? Zum Beispiel habe ich versucht, die Methodeneinladung von Association::UsersController zu vererben, um Vererbung zu verwenden, aber ich bin ein bisschen verwirrt, wie man es macht. Können Sie mir sagen, wie Sie diese Methode umschreiben würden, wenn die Association::UsersController von der usersController erbt. Hier ist, wie beide Controller wie folgt aussehen:

users_controller.rb:

class Api::V1::UsersController < Api::V1::BaseController 
    skip_after_action :verify_authorized, only: [:invite, :update_specific, :show] 
    before_action :set_user, except: [:invite, :index, :update_specific] 
    before_action :set_account, only: [:index, :invite, :show] 

    # creates user linked to account/only account owner can create users linked to account 
    # input account_id & email 
    def invite 
    unless current_user.id != @account.admin_user_id 
     user_already_exists_or_email_blank? 
     set_new_user 
     ActiveRecord::Base.transaction do 
     set_hotels_access 
     save_user_and_send_invitation_email 
     end 
    else 
     render_error("not_admin") 
    end 
    end 

    def show 
    if ((current_user == @user) || (@account.admin == current_user)) 
    else 
     render_error("unauthorized") 
    end 
    end 

    # admin can update employee or manager 
    def update_specific 
    @user_to_update = User.find(params[:id]) 
    if @user_to_update.account != current_user.created_account 
     render_error("unauthorized") 
    else 
     ActiveRecord::Base.transaction do 
     update_user_and_hotels_access 
     end 
    end 
    end 

    # update self 
    def update 
    authorize @user 
    if @user.update(user_params) 
     render_success("updated") 
    else 
     render_error("") 
    end 
    end 

    def destroy 
    authorize @user 
    if @user.destroy 
     render json: {message: "User successfully destroyed"} 
    else 
     render json: {error: "There was an error please try again"} 
    end 
    end 
    # envoyer account params 
    def index 
    if (current_user.created_account == @account) || ((current_user.account == @account) && (current_user.status == "manager")) 
     @users = policy_scope(User).where(account: @account) 
     @admin = @account.admin 
     render json: {users: @users, admin: @admin} 
    else 
     render json: {message: "Unauthorized"} 
    end 
    end 

    # unlincks user from account 
    #input user_id 
    def unlinck 
    authorize @user 
    @user.account = nil 
    if @user.save && @user.hotels.delete_all.nil? 
     render json: {user: @user} 
    else 
     render_error("db") 
    end 
    end 

    private 

    def user_already_exists_or_email_blank? 
    if User.find_by_email(params[:user][:email]) 
     render_error("mail_exists") and return 
    elsif params[:user][:email].blank? 
     render_error("empty_email") and return 
    end 
    end 

    def set_new_user 
    password = SecureRandom.hex 
    invitation_token = SecureRandom.uuid 
    @user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_id: params[:user][:account_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "hotel") 
    end 

    def set_hotels_access 
    if params[:hotel_access].first == "all" 
     @hotels = @account.hotels 
    else 
     @hotels = Hotel.where(id: params[:hotel_access]) 
    end 
    end 

    def save_user_and_send_invitation_email 
    if @user.save && @user.hotels << @hotels 
     if UserMailer.send_invitation(@user, params[:app_base_url]).deliver_now 
     @user.invitation_sent_at = Time.now 
     if @user.save 
      render_success("mail_sent") 
     else 
      render_error("db") 
     end 
     else 
     render_error("mail_processing") 
     end 
    else 
     render_error("db") 
    end 
    end 

    def update_user_and_hotels_access 
    @hotels = Hotel.where(id: params[:hotel_access]) 
    if @user_to_update.hotels.destroy_all 
     if @user_to_update.hotels << @hotels 
     if @user_to_update.update(user_params) 
      render json: {message: "User successfully updated"} 
     else 
      render_error("db") 
     end 
     else 
     render("db") 
     end 
    else 
     render_error("db") 
    end 
    end 

    def set_user 
    @user = User.find(params[:id]) 
    end 

    def set_account 
    if params[:account_id] 
     @account = Account.find(params[:account_id]) 
    elsif params[:user][:account_id] 
     @account = Account.find(params[:user][:account_id]) 
    end 
    end 

    def user_params 
    params.require(:user).permit(
     :email, 
     :account_id, 
     :first_name, 
     :last_name, 
     :telephone, 
     :position, 
     :status, 
     :user_id 
    ) 
    end 

    def render_error(error_type) 
    case error_type 
     when "not_admin" 
     render json: {error: "You are not allowed to create a user for this account"} 
     when "mail_exists" 
     render json: {error: "Please fill the email field and try again"} 
     when "empty_email" 
     render json: {error: "Please fill the email field and try again"} 
     when "mail_processing" 
     render json: { error: "We couldnt send an email to your invitee. Please try again" } 
     when "db" 
     render json: {error: "An error occured. Please try again"} 
     when "unauthorized" 
     render json: {error: "Unauthorized"} 
     else 
     render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity 
    end 
    end 

    def render_success(success_type) 
    case success_type 
     when "mail_sent" 
     render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." } 
     when "password_changed" 
     render json: {success: "Your password was successfully changed"} 
     when "updated" 
     render json: {success: "Your infos were successfully updated"} 
    end 
    end 

end 

Verband/users_controller.rb

class Api::V1::Association::UsersController < Api::V1::BaseController 
    skip_after_action :verify_authorized, only: [:invite, :update_specific, :show] 
    before_action :set_user, except: [:invite, :index, :update_specific] 
    before_action :set_account_asso, only: [:index, :show, :invite] 

    # creates user linked to account/only account owner can create users linked to account 
    # input account_id & email 
    def invite 
    unless current_user.id != @account_asso.admin_user_id 
     user_already_exists_or_email_blank? 
     set_new_user 
     ActiveRecord::Base.transaction do 
     set_offices_access 
     save_user_and_send_invitation_email 
     end 
    else 
     render_error("not_admin") 
    end 
    end 

    def show 
    if ((current_user == @user) || (@account_asso.admin == current_user)) 
    else 
     render_error("unauthorized") 
    end 
    end 

    # admin can update employee or manager 
    def update_specific 
    @user_to_update = User.find(params[:id]) 
    if @user_to_update.account != current_user.created_account 
     render_error("unauthorized") 
    else 
     ActiveRecord::Base.transaction do 
     update_user_and_offices_access 
     end 
    end 
    end 

    # update self 
    def update 
    authorize @user 
    if @user.update(user_params) 
     render_success("updated") 
    else 
     render_error("db") 
    end 
    end 

    def destroy 
    authorize @user 
    if @user.destroy 
     render json: {message: "User successfully destroyed"} 
    else 
     render_error("db") 
    end 
    end 
    # envoyer account params 
    def index 
    if (current_user.created_account_asso == @account_asso) || ((current_user.account_asso == @account_asso) && (current_user.status == "manager")) 
     @users = policy_scope(User).where(account_asso: @account_asso) 
     @admin = @account_asso.admin 
     render json: {users: @users, admin: @admin} 
    else 
     render_error("unauthorized") 
    end 
    end 

    # unlincks user from account 
    #input user_id 
    def unlinck 
    authorize @user 
    @user.account_asso = nil 
    if @user.save && @user.offices.delete_all.nil? 
     render json: {user: @user} 
    else 
     render_error("db") 
    end 
    end 

    private 

    def user_already_exists_or_email_blank? 
    if User.find_by_email(params[:user][:email]) 
     render_error("mail_exists") and return 
    elsif params[:user][:email].blank? 
     render_error("empty_email") and return 
    end 
    end 

    def set_new_user 
    password = SecureRandom.hex 
    invitation_token = SecureRandom.uuid 
    @user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_asso_id: params[:user][:account_asso_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "asso") 
    end 

    def set_offices_access 
    if params[:office_access].first == "all" 
     @offices = account_asso.offices 
    else 
     @offices = Office.where(id: params[:office_access]) 
    end 
    end 

    def save_user_and_send_invitation_email 
    if @user.save && @user.offices << offices 
     if UserMailer.send_invitation(@user, params[:app_base_url]).deliver_now 
     @user.invitation_sent_at = Time.now 
     if @user.save 
      render_success("mail_sent") 
     else 
      render_error("db") 
     end 
     else 
     render_error("mail_processing") 
     end 
    else 
     render_error("db") 
    end 
    end 

    def update_user_and_offices_access 
    @offices = Office.where(id: params[:office_access]) 
    if @user_to_update.offices.destroy_all 
     if @user_to_update.offices << @offices 
     if @user_to_update.update(user_params) 
      render json: {message: "User successfully updated"} 
     else 
      render_error("db") 
     end 
     else 
     render("db") 
     end 
    else 
     render_error("db") 
    end 
    end 

    def set_user 
    @user = User.find(params[:id]) 
    end 

    def set_account_asso 
    if params[:account_asso_id] 
     @account_asso = AccountAsso.find(params[:account_asso_id]) 
    elsif params[:user][:account_asso_id] 
     @account_asso = AccountAsso.find(params[:user][:account_asso_id]) 
    end 
    end 

    def user_params 
    params.require(:user).permit(
     :email, 
     :account_id, 
     :first_name, 
     :last_name, 
     :telephone, 
     :position, 
     :status, 
     :user_id 
    ) 
    end 

    def render_error(error_type) 
    case error_type 
     when "not_admin" 
     render json: {error: "You are not allowed to create a user for this account"} 
     when "mail_exists" 
     render json: {error: "Please fill the email field and try again"} 
     when "empty_email" 
     render json: {error: "Please fill the email field and try again"} 
     when "mail_processing" 
     render json: { error: "We couldnt send an email to your invitee. Please try again" } 
     when "db" 
     render json: {error: "An error occured. Please try again"} 
     when "unauthorized" 
     render json: {error: "Unauthorized"} 
     else 
     render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity 
    end 
    end 

    def render_success(success_type) 
    case success_type 
     when "mail_sent" 
     render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." } 
     when "password_changed" 
     render json: {success: "Your password was successfully changed"} 
     when "updated" 
     render json: {success: "Your infos were successfully updated"} 
    end 
    end 

end 

Vielleicht sollte ich das usersController dem Konzept von Hotel verbunden rewritte oder vielleicht sollte ich ein drittes superusersController erstellen, von dem sowohl der userController, der mit dem Konzept des Hotels verknüpft ist, als auch der usersController, der mit dem Assoziationskonzept verknüpft ist, erben würde? Können Sie mir helfen, die beste Lösung für meine Situation zu finden?

+3

Ich würde mich darauf konzentrieren, zuerst den Controller-Code zu beheben; Diese Methoden sind * weit * zu verschachtelt und fast unmöglich zu verstehen. * Dann * sehen, ob es ein gemeinsames Verhalten gibt, * dann * bestimmen * wie * dieses Verhalten zu teilen. –

+0

Ja, es gibt eine Menge nutzloser Duplizierung zwischen diesen beiden Controllern. Das heißt, ich bin mir nicht sicher, ob das Problem so groß ist, dass es sich um Ihr Datenmodell handelt oder wie Sie darüber nachdenken. Der "beste" Weg, um fortzufahren, geht wahrscheinlich über das Auslügen von Dumme-Verhalten in eine Super-Klasse hinaus, aber es ist sicherlich ein Ort, um anzufangen. Aber trotzdem: Dieser Code ist ziemlich schwer zu lesen. –

+0

danke @DaveNewton, ich folge deinem Rat und beginne, einige Code in Methoden zu extrahieren –

Antwort

1

Sie können sich Serviceobjekte ansehen. Sie sind einfach nur alte Ruby-Objekte. Sie können Ihre invite Methode in etwas wie UsersService#invite extrahieren und dann von beiden Controllern aufrufen. Unterschiede in der Logik können durch Übergeben eines Parameters in dem Kontext, in dem es ausgeführt wird (Benutzer oder Zuordnungen) behandelt werden.

+0

danke @Ruslan. Sie glauben also nicht, dass es eine gute Wahl ist, die Vererbung zu verwenden? –

+0

@Dave Wahrscheinlich nicht in diesem Fall. Es sei denn, Sie planen, diesen Code mit vielen anderen Controllern zu teilen. Alles ist eine Lösung, wenn es funktioniert, aber für diesen Fall sollten Mixins oder Service-Objekte den Zweck erfüllen – Ruslan

Verwandte Themen