0

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>
Seong Kim
  • 535
  • 5
  • 22

1 Answers1

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

Community
  • 1
  • 1
Xavier
  • 3,423
  • 23
  • 36
  • Regarding your update, I see that on line 8 you have `textbook.title` instead of `@textbook.title`. Try adding the `@` and see what happens with that. Thanks for the update! – Xavier Apr 17 '16 at 20:40
  • I fixed I get error another error. I will post it on my question Update section – Seong Kim Apr 17 '16 at 20:45
  • What is the relationship between `Contact` and `Textbook`? In your `textbook#show` action, how are you getting `@contact`? – Xavier Apr 17 '16 at 20:53
  • I didn't declare any relationship between "Contact" and "Textbook". I have only "Textbook" belong_to :user, and "User" has_many :textbooks. Zeiv, I am truly sorry about this. I am kinda newbie.. but I really want to make this happend and make myself understood. Can you please guide me to the solution? Thanks you very much in advance! – Seong Kim Apr 17 '16 at 20:59
  • I just added more details on Update section. – Seong Kim Apr 17 '16 at 21:04
  • Wow, Zeiv I appreciate so much!. I am implementing your solution right now.. probably it will take about at least an hour.. to make work. I really thank your expert knowledges. I will keep post it on here!! – Seong Kim Apr 18 '16 at 00:28
  • Is this get `contact", to: "textbook#new_contact", as: "new_contact"` => `get "contact", to: "textbooks#new_contact", as: "new_contact"` ? – Seong Kim Apr 18 '16 at 01:51
  • Hi Zeiv, I get error... I am so exhausted to fix this error... I updated section UPDATE2 on my question post. I thought it will work but keep giving me error.. – Seong Kim Apr 18 '16 at 03:06
  • OK now time is 04/18/2016 1:50am. I got to work into the page `/textbook/24/contact` but when I click 'Send message' I get error. `undefined method send_contact' for Contact:Class` on line `if Contact.send_contact(@textbook, current_user, message).deliver flash[:success] = "Email sent."` – Seong Kim Apr 18 '16 at 05:50
  • I just updated my answer. See here for exactly what I changed: http://stackoverflow.com/posts/36673518/revisions – Xavier Apr 18 '16 at 16:08
  • I stubbed out a test rails app with the above code, so it will be easier for me to follow along with you and test it. It works for me using the above with sendgrid. – Xavier Apr 18 '16 at 16:09
  • I uploaded my test app to GitHub, in case it is helpful for you to see all my code: https://github.com/zeiv/supreme-telegram – Xavier Apr 18 '16 at 16:18
  • One last question before I do fix all things. Do I have to remove `MailForm::Base` ?? I was using mail_from gem. – Seong Kim Apr 18 '16 at 17:38
  • You don't have to, but my code above and on GitHub assumes that you arne't using the gem. I used my own implementation of an email form. – Xavier Apr 18 '16 at 18:03
  • Got it! I will try implement it! – Seong Kim Apr 18 '16 at 18:26
  • I guess I have to follow the ActionMailer instead of using Mail_Form gem. – Seong Kim Apr 18 '16 at 20:17
  • OMG It is working!!! But do you know why am I keep getting empty body? I get right subject and etc but just empty body.. – Seong Kim Apr 19 '16 at 01:32
  • Your `:message` param must be getting lost somewhere. Double check the contact form, the textbook controller, and the contact mailer against mine to see if that is happening. Also double check your mailer views to make sure you're actually using the `@message` variable, as in here: https://github.com/zeiv/supreme-telegram/tree/master/app/views/contact – Xavier Apr 19 '16 at 03:48
  • Wow, I added `send_contact.html.erb` in wrong folder!! Everything works fine!!! Zeiv I appreciate!!! You are the best! – Seong Kim Apr 19 '16 at 04:26
  • @ziev The mailer working perfect! I really thank you! Now I am trying to use Bootstrap modal popup when a user clicks the `Contact`. If you have a time.. please take a look at this link. http://stackoverflow.com/questions/36734438/how-to-use-bootstrap-modal-popup-window-to-send-an-email-in-rails-4 – Seong Kim Apr 20 '16 at 05:19