Rails 4 - 使用纯文本和ERB进行闪回警报

时间:2016-08-23 23:40:05

标签: ruby-on-rails ruby

我不确定我对待它的方式是问题,还是ERB。

现在,当用户注册时,我发送了一封激活邮件。如果他们没有激活,并尝试重新登录,则会提示他们“抱歉,您未经授权。”我想修改它,以便让他们重新发送电子邮件。

SessionsController

class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      if user.activated?
        log_in user
        params[:session][:remember_me] == '1' ? remember(user) : forget(user)
        redirect_back_or user
      else
        message  = "Account not activated. "
        message += "Check your email for the activation link, or click" + <%= link_to "here", :controller => :user, :action => :resend_email  %>+ "to have it resent!"
        flash[:warning] = message
        redirect_to root_url
      end
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
  end

end

在Users控制器中,我创建了一个'resend_email'函数。基本上只是创建一个的大部分,所以有点多余。

UsersController

class UsersController < ApplicationController
    before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
    before_action :correct_user,   only: [:edit, :update]
    before_action :admin_user,     only: :destroy

  def index
    @users = User.where(activated: true).paginate(page: params[:page])
  end

  def show
    @user = User.find(params[:id])
    redirect_to root_url and return unless @user.activated?
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end

  def resend_email
     @user.send_activation_email
     flash[:info] = "Please check your email to activate your account."
     redirect_to root_url
  else

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

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end

    # Before filters

    # Confirms a logged-in user.
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

    # Confirms the correct user.
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

end

我尝试将“消息”修改为几个不同的版本,每次我得到类似

的响应
/home/ubuntu/workspace/sample_app/app/controllers/sessions_controller.rb:16: syntax error, unexpected '<' <%= link_to "here", :controlle... ^ /home/ubuntu/workspace/sample_app/app/controllers/sessions_controller.rb:16: syntax error, unexpected ',', expecting keyword_end ...o "here", :controller => :user, :action => :resend_email %> ... ^ /home/ubuntu/workspace/sample_app/app/controllers/sessions_controller.rb:16: syntax error, unexpected '>' ...r, :action => :resend_email %> ... ^

我从以前的经验中得到了这种语法,并且有类似需求的人。

所以我想知道最好的方法是什么,没有宝石(我确实找到了Devise功能,但我正在努力学习如何自己动手)

我还读到有时ERB和纯文本不能很好地工作。但是,我也收到错误,邮件只有<%= link_to "here", :controller => :user, :action => :resend_email %>

我不确定是否需要任何其他控制器。

编辑信息

将原始副本留给有此问题的其他人。 在阅读了下面答案中提供的max之后,我修改了一些内容。

对SessionsController的更改

link = view_context.instance_exec do
  ERB.new("<%= link_to 'here', :controller => :users, :action => :resend_activation %>").result(binding)
end
message  = "Account not activated. "
message += "Check your email for the activation." 
message += link  # This is for demo purposes, just needed an output

用户控制器

def resend_activation      @user = User.find(params [:email])      @ user.send_activation_email      flash [:info] =“请检查您的电子邮件以激活您的帐户。”      redirect_to root_url   端

警告的部分视图

  <% flash.each do |message_type, message| %>
    <%= content_tag(:div, sanitize(message), class: "alert alert-#{message_type}") %>
  <% end %>

到目前为止,我现在看到了我期望的链接,而我的问题是当我点击它时。

Couldn't find User with 'id'= - 我尝试了User的不同用法,甚至根据电子邮件参数进行了重新搜索。

所以我尝试将路线更新为

路线

Rails.application.routes.draw do

  root 'static_pages#home'
  get '/home', to: 'static_pages#home'
  get '/help', to: 'static_pages#help'
  get '/about', to: 'static_pages#about'
  get '/contact', to: 'static_pages#contact'
  get '/signup', to: 'users#new'
  post '/signup', to: 'users#create'
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users
  resources :account_activations, only: [:edit]
  post '/resend_activation:email'  =>  'account_activations#resend_activation',
                                        :constraints => { :email => /[^\/]+/ }
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

取得了进展(我认为),它现在提示我“找不到资源”。我正在研究何时使用get vs post,我认为我采用了正确的方法。但是,为什么在发送电子邮件之后它会尝试引用该路径,它应该返回root_url?

再次感谢。

更新#2

我能够通过添加路由开关并将 sessions_controller 修改为

来停止错误
  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      if user.activated?
        log_in user
        params[:session][:remember_me] == '1' ? remember(user) : forget(user)
        redirect_back_or user
      else
        message  = "Account not activated. "
        message += "Check your email for the activation." 
        message += " #{view_context.link_to "Resend Activation E-Mail", { action: "resend_activation",
        controller: "account_activations", email: user.email }, method: :post}"
        flash[:warning] = message
        redirect_to root_url
      end
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

但是现在没有电子邮件出来,所有东西都只是路由回登录。

heroku logs --tail

告诉我

Heroku Logs

2016-08-24T09:44:48.990703+00:00 app[web.1]: I, [2016-08-24T09:44:48.990609 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67] Started GET "/resend_activation/test@example.com" for 100.15.65.126 at 2016-08-24 09:44:48 +0000
2016-08-24T09:44:48.992317+00:00 app[web.1]: I, [2016-08-24T09:44:48.992217 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67] Processing by StaticPagesController#home as 
2016-08-24T09:44:48.992394+00:00 app[web.1]: I, [2016-08-24T09:44:48.992349 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Parameters: {"email"=>"test@example.com"}
2016-08-24T09:44:48.997712+00:00 app[web.1]: I, [2016-08-24T09:44:48.997648 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendering static_pages/home.html.erb within layouts/application
2016-08-24T09:44:48.999032+00:00 app[web.1]: I, [2016-08-24T09:44:48.998965 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered static_pages/home.html.erb within layouts/application (1.1ms)
2016-08-24T09:44:49.010260+00:00 app[web.1]: I, [2016-08-24T09:44:49.010186 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered layouts/_shim.html.erb (0.4ms)
2016-08-24T09:44:49.010516+00:00 app[web.1]: I, [2016-08-24T09:44:49.010461 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered layouts/_shim.html.erb (0.0ms)
2016-08-24T09:44:49.010642+00:00 app[web.1]: I, [2016-08-24T09:44:49.010591 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered layouts/_headElement.html.erb (7.6ms)
2016-08-24T09:44:49.020206+00:00 app[web.1]: D, [2016-08-24T09:44:49.020136 #5] DEBUG -- : [8cfcee3c-133c-489e-8877-523578821d67]   User Load (1.8ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 103], ["LIMIT", 1]]
2016-08-24T09:44:49.020630+00:00 app[web.1]: I, [2016-08-24T09:44:49.020565 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered layouts/_header.html.erb (3.8ms)
2016-08-24T09:44:49.025024+00:00 app[web.1]: I, [2016-08-24T09:44:49.024957 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67]   Rendered layouts/_footer.html.erb (0.7ms)
2016-08-24T09:44:49.025337+00:00 app[web.1]: I, [2016-08-24T09:44:49.025273 #5]  INFO -- : [8cfcee3c-133c-489e-8877-523578821d67] Completed 200 OK in 33ms (Views: 26.1ms | ActiveRecord: 1.8ms)

找到该成员并呈现它,但不再发送邮件。我认为这是因为我必须建立起来让它“工作”的路线?

2 个答案:

答案 0 :(得分:2)

使用以下代码:

    message += 
      "..."" +
      <%= link_to "here", :controller => :user, :action => :resend_email  %> + 
      "..."

你试图在普通红宝石中使用ERB标签 - 这是行不通的。您只能在模板中使用ERB。

通常情况下,我建议使用Ruby的标准#{}字符串插值,但这实际上并不能解决问题。

link_to默认情况下仅供视图使用,但您可以通过view_context对象访问它:

link = "#{view_context.link_to 'here', :controller => :user, :action => :resend_email}"

顺便说一句,如果您自己编译ERB,可以在控制器中使用ERB:

link = ERB.new("<%= view_context.link_to(...) %>").result(binding)

您可以通过在不同的上下文中调用ERB来更改可用的变量/方法,例如:

link = view_context.instance_exec do
  ERB.new("<%= link_to(...) %>").result(binding)
end

这也适用于标准#{}字符串插值:

link = view_context.instance_exec do
  "#{link_to(...)}"
end

值得一提的是,如果你在控制器中创建一个自定义html字符串(就像你在这里用flash做的那样),当你在视图上显示文本时,你需要添加一些自定义方法来使html显示为真实HTML:

# in controller
flash[:test] = "<span>some html</span>"

# in view
<%= raw flash[:test].html_safe %>

这样只会显示文字some html,而不会显示整个字符串<span>some html</span>

有一个原因rawhtml_safe是必要的,因为打印html存在安全风险,而Rails旨在使其更加困难。

假设您的用户将其用户名设置为"<script>alert("hacked")</script>",并且此字符串以某种方式将其作为真正的html进入页面。您只需将用户暴露给XSS(跨站点脚本),您不想这样做。因此,请确保在使用raw <string>.html_safe时,显示用户生成的任何内容。

答案 1 :(得分:0)

您的路由告诉您id = nil的原因是因为您的:activation_token是该路由中的id并且它未存储在数据库中,它是使用{虚拟创建的} {1}}。而是将attr_accessor存储为数据库中的列。