Ruby on rails Rails 4:如何在这种长控制器方法中解耦逻辑?
我正在使用Ruby on rails Rails 4:如何在这种长控制器方法中解耦逻辑?,ruby-on-rails,authentication,controller,refactoring,Ruby On Rails,Authentication,Controller,Refactoring,我正在使用has\u secure\u password和rails 4.1.5应用程序。我想将我的登录功能与我的sessioncontroller分离,这样我就可以在我的应用程序中的任何位置重用它来登录任何用户-例如注册后登录用户,记录分析事件等 因此,我将代码重构为一个LoginUser服务对象,我对此感到满意 问题是在重构之后,我的控制器仍然有一些耦合逻辑。我正在使用一个表单对象(通过reform gem)进行表单验证,然后将用户、会话和密码传递给LoginUser服务 以下是mySess
has\u secure\u password
和rails 4.1.5
应用程序。我想将我的登录功能与我的sessioncontroller
分离,这样我就可以在我的应用程序中的任何位置重用它来登录任何用户-例如注册后登录用户,记录分析事件等
因此,我将代码重构为一个LoginUser
服务对象,我对此感到满意
问题是在重构之后,我的控制器仍然有一些耦合逻辑。我正在使用一个表单对象(通过reform gem)进行表单验证,然后将用户、会话和密码传递给LoginUser
服务
以下是mySessionController
中的创建方法的外观:
def create
login_form = Forms::LoginForm.new(User.new)
if login_form.validate(params[:user]) # validate the form
begin #find the user
user = User.find_by!(email: params[:user][:email])
rescue ActiveRecord::RecordNotFound => e
flash.now.alert = 'invalid user credentials'
render :new and return
end
else
flash.now.alert = login_form.errors.full_messages
render :new and return
end
user && login_service = LoginUser.new(user, session, params[:user][:password])
login_service.on(:user_authenticated){ redirect_to root_url, success: "You have logged in" }
login_service.execute
end
一切正常,但我不满意的是验证表单,然后在将表单发送到服务对象之前找到用户之间的捆绑逻辑。而且,多个闪光警报感觉……嗯……不对
如何通过将这两种方法解耦,使此方法变得更好?现在看起来一个背着另一个
这里是我的登录用户
服务对象,供您参考
class LoginUser
include Wisper::Publisher
attr_reader :user, :password
attr_accessor :session
def initialize(user, session, password)
@user = user
@session = session
@password = password
end
def execute
if user.authenticate(password)
session[:user_id] = user.id
publish(:user_authenticated, user)
else
publish(:user_login_failed)
end
end
end
这里最让我印象深刻的是,
create
是一种具有多重责任的方法,可以/应该被隔离
我看到的责任是:
def create
validate_form(user_params); return if performed?
user = find_user_for_authentication(user_params); return if performed?
login_service = LoginUser.new(user, session, user_params[:password])
login_service.on(:user_authenticated){ redirect_to root_url, success: "You have logged in" }
login_service.execute
end
private
def user_params
params[:user]
end
def validate_form(attrs)
login_form = Forms::LoginForm.new(User.new)
unless login_form.validate(attrs)
flash.now.alert = login_form.errors.full_messages
render :new
end
end
def find_user_for_authentication(attrs)
if (user = User.find_by_email(attrs[:email]))
user
else
flash.now.alert = 'invalid user credentials'
render :new
end
end
请注意,如果执行返回?
条件将检查是否调用了渲染
或重定向到
方法。如果是这样,将调用return
,并提前完成create
操作,以防止出现双重渲染/重定向错误
我认为这是一个很大的进步,因为责任被分成了几个不同的方法。这些方法在很大程度上注入了它们的依赖关系,因此它们在未来也可以继续自由发展。这是一个令人惊讶的答案。我的
登录用户
对象的问题在于,它需要原始密码输入作为依赖项,我发现很难通过需要使用我的登录用户
服务的其他对象传递这些信息。有什么办法可以解决这个问题吗?对不起,我不太明白这个问题。为什么传递原始密码很难?我认为在任何登录场景中,您都可以使用原始密码。也许用代码提出一个新问题,并将其链接到我?