在 Hartl 的教程中添加联系表
Add a contact form to Hartl's tutorial
我正在学习 Rails,方法是遵循 Hartl 的教程并对其进行自己的调整。现在,我想扩展它并添加一个发送电子邮件的联系表。本教程中不包含此类内容,但在第 10 章结束时,我们学会了使用邮件程序方法并在 Heroku 上配置了 SendGrid。
我已经在路线中设置了视图,我认为还需要执行以下额外步骤:
1) 终端。 rails 生成邮件 ContactForm
2) 在 app/mailers/contactform.rb:
def send_contactform_email(visitor)
@visitor = visitor
mail( :to => myemail@example.com, :from => visitor.email, :subject => 'Contact form' )
end
3) app/views/contactform_mailer/(邮件消息的视图)例如:
<h1>Website contact form</h1>
<p>On <$= ... %> <%= "#{@visitor.name} (#{@visitor.email} sent the following message:" %></p>
<p><%= @visitor.message %></p>
4) app\controllers\static_pages_controller (或其他位置?)
# Sends contact form email.
def send_contact_form_email
ContactFormMailer.send_contactform_email(visitor).deliver_now
redirect_to contact_path, notice: 'Message sent'
end
5) app\views\static_pages\contact.html.erb (我不确定第一行,我是否也应该在 routes.rb 中做点什么?我的猜测是第一行必须告诉执行步骤 4 中的方法,这不会像现在这样工作。)
<%= form_for(:static_pages, url: contactform_path) do |f| %>
<i class="pt-row-icon glyphicon glyphicon-user"></i> <%= f.label :name %>
<%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :email %>
<%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :message %>
<%= f.text_area :message, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
我认为这还不是 100% 正确,尤其是粗体部分。你有什么想法?
更新,版本 2: 我已尝试按照 Ven 的建议进行更新,现在有以下代码。据我了解,这个想法是
def contact
中的控制器设置@message 变量。
- form_for 知道它应该用 params[:message].
填充这个变量
- 控制器采用 form_for 中的值并将它们传递给邮件程序。
- 邮件程序使用邮件程序视图设计要发送的消息。
- 邮件程序将其发回给发送消息的控制器。
1) App/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
before_action :valid_email?, only: [:send_message_email]
# Shows the contact form page
def contact
@message = message(message_params)
end
# Sends the message.
def send_message_email
@message = message(message_params)
if @message.valid?
MessageMailer.new_message(@message).deliver_now
redirect_to contact_path, notice: "Your messages has been sent."
else
flash[:alert] = "An error occurred while delivering this message."
render :new
end
end
private
def message_params
params.require(:message).require(:name, :email, :content)
end
def valid_email?(email)
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
email.present? && (email =~ VALID_EMAIL_REGEX)
end
end
2) app\views\static_pages\contact.html.erb:
中的联系表
<%= form_for(message: params[:message], url: contact_path) do |f| %>
<%= f.label :name %> <%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<%= f.label :email %> <%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<%= f.label :content %> <%= f.text_area :content, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
3) Routes.rb
get 'contact' => 'static_pages#contact', as: 'contact'
post 'contact' => 'static_pages#send_message_email'
4) App/views/message_mailer.text.erb(和 html.erb)
<%= @message[:name] %> <%= @message[:email] %> wrote:
<%= @message[:content] %>
5) App/mailers/message_mailer.rb
class MessageMailer < ApplicationMailer
default to: "myemail@example.com>"
def new_message(message)
@message = message
mail to: "myemail@example.com"
mail from: @message[:email]
mail subject: "Message from #{message[:name]}"
end
end
现在,当我尝试访问服务器上的联系表时,我收到错误消息:param is missing or the value is empty: message
。它指的是 params.require(:message).require(:name, :email, :content)
行。不知道我做错了什么。将其更改为 params.require(:message).permit(:name, :email, :content)
没有任何区别。
4) app\controllers\static_pages_controller (or another location?)
这似乎是正确的,如果 this 是所述应用程序的 github 存储库。
def send_contact_form_email
您的控制器有问题:此操作将尝试发送电子邮件,无论它是在 POST 还是 GET 中使用。您应该使用两种不同的操作,一种用于显示视图(使用 GET),一种用于发送电子邮件(使用您创建的邮件程序 class)。 (此时,您可能想要创建另一个控制器)
ContactFormMailer.send_contactform_email(visitor).deliver_now
然后,继续:您传递给邮件程序的是 "visitor"。没有这样的变量。
您可能想访问 params
哈希(包含 GET 和 POST 请求的参数)之外的内容,并使用与您的表单相同的密钥(form_for(:visitor ...
=> params[:visitor]
(所以你想改变那个 :static_pages
))。
<p>On <$= ... %> <%= "#{@visitor.name} (#{@visitor.email} sent the following message:" %></p>
因为这个 returns 是一个对象,而不是散列,@visitor.email
需要在邮件程序中 @visitor[:email]
。
最后一件事:只需使用 params[:visitor]
就意味着人们可以将该字段留空。您可能想查看 Rails 4 中添加的强参数(这本书似乎有些过时了?)。
最后,您需要添加路由才能实现这些操作(一个用于 GET 请求 - 显示视图 - 一个用于 POST 请求 - 提交表单)。
PS:
mail( :to => myemail@example.com, :from => visitor.email, :subject => 'Contact form' )
警告:在这里,您忘记引用电子邮件地址。此外,您交换了 to
/from
参数。您想发送 TO 您的访客电子邮件,而不是从那里发送。
编辑
params.require(:message).require(:name, :email, :content)
这将需要所述密钥,但 AFAIK 与 :message
相同 "level" - 最上面的那个。你想使用 permit
:
params.require(:message) # require "namespace"
.permit(:name, :email, :content) # permit keys
@message = message(message_params)
message
函数在哪里定义的?
mail to: "myemail@example.com"
mail from: @message[:email]
mail subject: "Message from #{message[:name]}"
这会发送 3 封不同的电子邮件,因为您调用了 mail
函数 3 次。
我正在学习 Rails,方法是遵循 Hartl 的教程并对其进行自己的调整。现在,我想扩展它并添加一个发送电子邮件的联系表。本教程中不包含此类内容,但在第 10 章结束时,我们学会了使用邮件程序方法并在 Heroku 上配置了 SendGrid。
我已经在路线中设置了视图,我认为还需要执行以下额外步骤:
1) 终端。 rails 生成邮件 ContactForm
2) 在 app/mailers/contactform.rb:
def send_contactform_email(visitor)
@visitor = visitor
mail( :to => myemail@example.com, :from => visitor.email, :subject => 'Contact form' )
end
3) app/views/contactform_mailer/(邮件消息的视图)例如:
<h1>Website contact form</h1>
<p>On <$= ... %> <%= "#{@visitor.name} (#{@visitor.email} sent the following message:" %></p>
<p><%= @visitor.message %></p>
4) app\controllers\static_pages_controller (或其他位置?)
# Sends contact form email.
def send_contact_form_email
ContactFormMailer.send_contactform_email(visitor).deliver_now
redirect_to contact_path, notice: 'Message sent'
end
5) app\views\static_pages\contact.html.erb (我不确定第一行,我是否也应该在 routes.rb 中做点什么?我的猜测是第一行必须告诉执行步骤 4 中的方法,这不会像现在这样工作。)
<%= form_for(:static_pages, url: contactform_path) do |f| %>
<i class="pt-row-icon glyphicon glyphicon-user"></i> <%= f.label :name %>
<%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :email %>
<%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :message %>
<%= f.text_area :message, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
我认为这还不是 100% 正确,尤其是粗体部分。你有什么想法?
更新,版本 2: 我已尝试按照 Ven 的建议进行更新,现在有以下代码。据我了解,这个想法是
def contact
中的控制器设置@message 变量。- form_for 知道它应该用 params[:message]. 填充这个变量
- 控制器采用 form_for 中的值并将它们传递给邮件程序。
- 邮件程序使用邮件程序视图设计要发送的消息。
- 邮件程序将其发回给发送消息的控制器。
1) App/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
before_action :valid_email?, only: [:send_message_email]
# Shows the contact form page
def contact
@message = message(message_params)
end
# Sends the message.
def send_message_email
@message = message(message_params)
if @message.valid?
MessageMailer.new_message(@message).deliver_now
redirect_to contact_path, notice: "Your messages has been sent."
else
flash[:alert] = "An error occurred while delivering this message."
render :new
end
end
private
def message_params
params.require(:message).require(:name, :email, :content)
end
def valid_email?(email)
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
email.present? && (email =~ VALID_EMAIL_REGEX)
end
end
2) app\views\static_pages\contact.html.erb:
中的联系表<%= form_for(message: params[:message], url: contact_path) do |f| %>
<%= f.label :name %> <%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<%= f.label :email %> <%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<%= f.label :content %> <%= f.text_area :content, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
3) Routes.rb
get 'contact' => 'static_pages#contact', as: 'contact'
post 'contact' => 'static_pages#send_message_email'
4) App/views/message_mailer.text.erb(和 html.erb)
<%= @message[:name] %> <%= @message[:email] %> wrote:
<%= @message[:content] %>
5) App/mailers/message_mailer.rb
class MessageMailer < ApplicationMailer
default to: "myemail@example.com>"
def new_message(message)
@message = message
mail to: "myemail@example.com"
mail from: @message[:email]
mail subject: "Message from #{message[:name]}"
end
end
现在,当我尝试访问服务器上的联系表时,我收到错误消息:param is missing or the value is empty: message
。它指的是 params.require(:message).require(:name, :email, :content)
行。不知道我做错了什么。将其更改为 params.require(:message).permit(:name, :email, :content)
没有任何区别。
4) app\controllers\static_pages_controller (or another location?)
这似乎是正确的,如果 this 是所述应用程序的 github 存储库。
def send_contact_form_email
您的控制器有问题:此操作将尝试发送电子邮件,无论它是在 POST 还是 GET 中使用。您应该使用两种不同的操作,一种用于显示视图(使用 GET),一种用于发送电子邮件(使用您创建的邮件程序 class)。 (此时,您可能想要创建另一个控制器)
ContactFormMailer.send_contactform_email(visitor).deliver_now
然后,继续:您传递给邮件程序的是 "visitor"。没有这样的变量。
您可能想访问 params
哈希(包含 GET 和 POST 请求的参数)之外的内容,并使用与您的表单相同的密钥(form_for(:visitor ...
=> params[:visitor]
(所以你想改变那个 :static_pages
))。
<p>On <$= ... %> <%= "#{@visitor.name} (#{@visitor.email} sent the following message:" %></p>
因为这个 returns 是一个对象,而不是散列,@visitor.email
需要在邮件程序中 @visitor[:email]
。
最后一件事:只需使用 params[:visitor]
就意味着人们可以将该字段留空。您可能想查看 Rails 4 中添加的强参数(这本书似乎有些过时了?)。
最后,您需要添加路由才能实现这些操作(一个用于 GET 请求 - 显示视图 - 一个用于 POST 请求 - 提交表单)。
PS:
mail( :to => myemail@example.com, :from => visitor.email, :subject => 'Contact form' )
警告:在这里,您忘记引用电子邮件地址。此外,您交换了 to
/from
参数。您想发送 TO 您的访客电子邮件,而不是从那里发送。
编辑
params.require(:message).require(:name, :email, :content)
这将需要所述密钥,但 AFAIK 与 :message
相同 "level" - 最上面的那个。你想使用 permit
:
params.require(:message) # require "namespace"
.permit(:name, :email, :content) # permit keys
@message = message(message_params)
message
函数在哪里定义的?
mail to: "myemail@example.com"
mail from: @message[:email]
mail subject: "Message from #{message[:name]}"
这会发送 3 封不同的电子邮件,因为您调用了 mail
函数 3 次。