How can I grab or access different model attribute when I send email using Sendgrid Rails Heroku

半世苍凉 提交于 2019-12-12 02:13:30

问题


I am using devise, and scaffolded Textbook. I like to implement my strategy. When buyer clicks an @textbook.title -> Buyer can send an email to the @textbook's seller. I have every model has column for 'user_email' So, Whenever a seller create a @textbook, automatically current_user.email is saved into @textbook.user_email.

I just don't know how to grab the seller's user_email and send email.

I have following

Textbook model:

class Textbook < ActiveRecord::Base

    belongs_to :user

    validates :title, :presence => true
    validates :subject, :presence => true
    validates :price, :presence => true
    validates :offer, :presence => false
    validates :created_at, :presence => false
    validates :user_email, :presence => true
    validates :description, :presence => true
end

I am not sure this model syntax is right for subject and current_user.email Contact model:

class Contact < MailForm::Base
    attribute :name,      :validate => true
    attribute :current_user.email,     :validate => /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
    attribute :message, :validate => true

    def headers
        {
          :subject => "I like to buy #{@textbook.id.title}",
          :to => "@textbook.id.user_email",
          :from => %(<#{email}>)
        }
    end
end

My detail question is this: If a user clicks 'contact' when buyer was inside of a specific textbook ant it links the user to textbook#show. Below is the form when the user clicked 'contact'.

How can I make sure this below view access the correct textbook.id or textbook.title?

<h1> Contact to the Seller </h1>

<div>
    <%=form_for @contact do |f|%>
        <h3>Send email for: <%=@textbook.id.title%> </h3>

        <%= f.label :message %><br>
        <%= f.text_area :message, as: :text %><br>  

        <%=f.submit 'Send message', class: 'button' %>
    <%end%>
</div>

Specially, I don't know how to handle grab attributes that is from different model inside different views.

Thank you in advance!

-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!

Update 1:

I have contact controller like this:

class ContactsController < ApplicationController
    def new
        @contact = Contact.new
    end

    def create
        @contact = Contact.new(params[:contact])
        #@contact.request = request
        if @contact.deliver
            flash[:success] = "Email sent."
        else
            flash[:alert] = "Cannot send an email."
            render :new
        end
    end
end

I just edited my 'class Contact < MailForm::Base'

class Contact < MailForm::Base
attribute :name,      :validate => true
attribute :email,     :validate => /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
attribute :message, :validate => true

def headers
    {
      :subject => "I like to buy #{textbook.title}",
      :to => "@textbook.user_email",
      :from => %(<#{current_user.email}>)
    }
end

end

But I got error:

NameError in ContactsController#create
undefined local variable or method `textbook' for #<Contact:0x007fbac641be40>

Extracted source (around line #8):        
    def headers
        {
          :subject => "I like to buy #{textbook.title}",
          :to => "@textbook.user_email",
          :from => %(<#{current_user.email}>)
        }

@zeiv I fixed textbook.title -> @textbook.title I get error an another error.

NoMethodError in ContactsController#create
undefined method `title' for nil:NilClass
    def headers
        {
          :subject => "I like to buy #{@textbook.title}",
          :to => "@textbook.user_email",
          :from => %(<#{current_user.email}>)
        }

I have views/textbooks.html.erb:

<div class="container">

        <p>
          <h3><strong>Title:</strong>
          <%= @textbook.title %></h3>
        </p>

        <p>
          <strong>Subject:</strong>
          <%= @textbook.subject %>
        </p>

        <p>
          <strong>Price:</strong>
          $<%= @textbook.price %>
        </p>

        <p>
          <strong>Accept Offer:</strong>
          <%if @textbook.offer == true%>
            <%='Yes'%>
          <%else%>
            <%='No'%>
          <%end%>
        </p>

        <p>
          <strong>Description:</strong>
          <pre><%= @textbook.description %></pre>
        </p>

        <p>
          <strong>Image:</strong>
          <pre><%= image_tag @textbook.thumbnail.url(:medium) %></pre>
        </p>

        <p>
          <strong>Created on:</strong>
          <%= @textbook.created_at.strftime("%d %b. %Y") %>
        </p>

        <p>
            <%= link_to 'Contact', new_contact_path %>
        </p>

        <%if @textbook.user_email == current_user.email %>
            <%= link_to 'Edit', edit_textbook_path(@textbook) %> |
            <%= link_to 'Back to list', textbooks_path %>
        <%else %>
            <%= link_to 'Back to list', textbooks_path %>
        <%end%>

And I have textbooks_controller:

class TextbooksController < ApplicationController
  before_action :set_textbook, only: [:show, :edit, :update, :destroy]
  #before_action :set_textbook, only: [:show]
  #before_action :authorize_resource!, except: [:new, :index, :show]

  # GET /textbooks
  # GET /textbooks.json
  def index
    #@textbooks = Textbook.all
    @textbooks = Textbook.all.order(created_at: :desc).paginate(page: params[:page], per_page: 10)
    #@textbooks = Textbook.paginate(:page => params[:page], :per_page => 10)
  end

  # GET /textbooks/1
  # GET /textbooks/1.json
  def show
  end

I have config/routes:

resources :textbooks
  resources :contacts, only: [:new, :create]

  devise_for :users

When I rake routes at this moment 4/17 5:05pm

new_textbook GET    /textbooks/new(.:format)               textbooks#new
           edit_textbook GET    /textbooks/:id/edit(.:format)          textbooks#edit
                textbook GET    /textbooks/:id(.:format)               textbooks#show
                         PATCH  /textbooks/:id(.:format)               textbooks#update
                         PUT    /textbooks/:id(.:format)               textbooks#update
                         DELETE /textbooks/:id(.:format)               textbooks#destroy
                contacts POST   /contacts(.:format)                    contacts#create
             new_contact GET    /contacts/new(.:format)                contacts#new

UPDATE 2 -!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!#-!

below is after 04/17/2016 11:00pm @zeiv I did what you told me. But still I get error when I click 'contact' button in views/textbooks/show.html.erb

#views/textbooks/show.html.erb
<p>
    <%= link_to 'Contact', new_contact_textbook_path %>
</p>

my routes.rb has now:

Rails.application.routes.draw do

  resources :textbooks do
    member do
      get 'contact', to: 'textbooks#new_contact', as: 'new_contact'
      post 'contact', to: 'textbooks#send_contact', as: 'send_contact'
    end
  end

rake routes has now:

Prefix Verb   URI Pattern                            Controller#Action
    new_contact_textbook GET    /textbooks/:id/contact(.:format)       textbooks#new_contact
   send_contact_textbook POST   /textbooks/:id/contact(.:format)       textbooks#send_contact
               textbooks GET    /textbooks(.:format)                   textbooks#index
                         POST   /textbooks(.:format)                   textbooks#create
            new_textbook GET    /textbooks/new(.:format)               textbooks#new
           edit_textbook GET    /textbooks/:id/edit(.:format)          textbooks#edit
                textbook GET    /textbooks/:id(.:format)               textbooks#show
                         PATCH  /textbooks/:id(.:format)               textbooks#update
                         PUT    /textbooks/:id(.:format)               textbooks#update
                         DELETE /textbooks/:id(.:format)               textbooks#destroy

The error I get is this:

NoMethodError in Textbooks#new_contact

undefined method `id' for nil:NilClass
Extracted source (around line #4):
<div>
    Texbook id is: <%= @textbook.id %>
</div>

I am running heroku local the error shows:

10:56:13 PM web.1 |    Rendered textbooks/new_contact.html.erb within layouts/application (2.0ms)
10:56:13 PM web.1 |  Completed 500 Internal Server Error in 7ms (ActiveRecord: 0.1ms)
10:56:13 PM web.1 |  ActionView::Template::Error (undefined method `id' for nil:NilClass):
10:56:13 PM web.1 |      1: <h1> contact seller! - working? </h1>
10:56:13 PM web.1 |      2:
10:56:13 PM web.1 |      3: <div>
10:56:13 PM web.1 |      4:     Texbook id is: <%= @textbook.id %>
10:56:13 PM web.1 |      5: </div>

回答1:


Basically what you need to do is to write your mailers and controllers in such a way that all the information you want is passed to the mailer. So if you want an instance of your Textbook model to be passed to the mailer, you will need to do so from the controller in which you send your email. You might event want to nest your contact controller routes within your textbook routes to help you. Alternatively, rather than having an entire controller for Contact, just have a contact action within your textbook controller.

# route.rb
...
resources :textbooks do
  member do
    get "contact", to: "textbooks#new_contact", as: "new_contact"
    post "contact", to: "textbooks#send_contact", as: "send_contact"
  end
end

That will give you routes like /textbook/24/contact. member do means that the routes are for individual instances of your model rather than the whole collection, so you will need to specify which textbook you are referring to when calling their helpers: new_contact_textbook_path(@textbook.id).

So in your Textbook controller, you would do this:

# textbooks_controller.rb
before_action :set_textbook, only: [:show, :edit, :update, :destroy, :new_contact, :send_contact]
...
def new_contact
  # We are NOT doing Contact.new here
  # Only put logic here that you need to display the form
end

def send_contact
  message = params[:message]
  if Contact.send_contact(@textbook, current_user, message).deliver
    flash[:success] = "Email sent."
    redirect_to @textbook
  else
    flash[:alert] = "There was a problem sending the email."
    render :new_contact
  end
end

Then put your new_contact.html.erb file in with your other Textbook views.

<h1> Contact to the Seller </h1>

<div>
    <%= form_tag send_contact_textbook_path(@textbook.id) do %>
        <h3>Send email for: <%=@textbook.title%> </h3>

        <%= label_tag :message, "Type your message:" %><br>
        <%= text_area_tag :message %><br>  

        <%= submit_tag 'Send message', class: 'button' %>
    <%end%>
</div>

Notice that I'm using form_tag instead of form_for because we don't have a Contact object to pass it. (That is, Contact isn't a model. It's a mailer.)

Your mailer would then look something like this:

class Contact < ApplicationMailer

  def send_contact(textbook, current_user, message)
    @textbook = textbook
    @current_user = current_user
    @message = message
    mail(
      from: "#{@current_user.name} <#{@current_user.email}>",
      to: @textbook.user.email,
      subject: "I would like to buy #{@textbook.title}",
      reply_to: @current_user.email,
    )
  end
end

And finally, put the template/view for you mailer in /app/views/contact/send_contact.html.erb:

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1><%= @current_user.name %> is wondering about <%= @textbook.title %>:</h1>
    <p><%= @message %></p>
  </body>
</html>

And that should do it! Although you may have to adjust some things to suit your needs. Also see these links for more examples:

Contact Form Mailer in Rails 4

https://sendgrid.com/docs/Integrate/Frameworks/rubyonrails.html



来源:https://stackoverflow.com/questions/36672859/how-can-i-grab-or-access-different-model-attribute-when-i-send-email-using-sendg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!