Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
class ApplicationController < ActionController::Base
before_filter :set_mailer_host

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception

def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration stuff like like can go in either config/application.rb or config/environments/env-specific-config. that way it's set when the app loads up.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, moved it to development.rb. If I set it in either of those locations then it will be a literal assignment, right? Suppose that's good enough if made per env. I liked the idea of using the request to provide the host info. Seemed more flexible.

end
end
16 changes: 7 additions & 9 deletions app/controllers/messages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,20 @@ def show
def create
@message = Message.new(message_params)
@message.message_id = SecureRandom.uuid;
@message.authenticated = [email protected]?

respond_to do |format|
if @message.save
format.html { redirect_to action: 'index', notice: 'Message was successfully created.' }
else
format.html { render :new }
end
if @message.save
MessageMailer.sd_message(@message).deliver_now
redirect_to action: 'index', notice: 'Message was successfully created.'
else
render :new
end
end

# DELETE /messages/1
def destroy
@message.destroy
respond_to do |format|
format.html { redirect_to action: 'index', notice: 'Message was successfully destroyed.' }
end
redirect_to action: 'index', notice: 'Message was successfully destroyed.'
end

private
Expand Down
41 changes: 41 additions & 0 deletions app/controllers/recipients_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class RecipientsController < ApplicationController

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since most of the logic below is operating upon a message object, this code should probably be moved to the MessagesController. By convention, each controller should apply to it's referenced model.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I split these apart mainly due to routing. I took a look at how tmwsd's message edit navigation progressed vs how the messages were actually read. It used different routes for message admin vs message consumption. I went with a similar approach, which lead to some ugliness with endpoint config.

  get 'recipients/:id' => 'recipients#show'
  get 'recipients/:id/authenticate' => 'recipients#authenticate'
  post 'recipients/:id' => 'recipients#authenticatedShow'

I liked this separation due to the distinctiveness of the recipient view and authentication flow against that of the admin flow.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, yeah that makes sense in context. I think the best thing to do here is to use semantic resources still, but namespace them for separation: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing.

This is trivial right now, and probably not necessary to perfect, as this is just a small learning app. The custom routes will work fine for this.


before_action :set_message

# GET /recipients/1
def show
if @message.authenticated?
@message.delete()
else
redirect_to action: 'authenticate'
end
end

# GET /recipients/1/authenticate
def authenticate
end

# POST /recipients/1
def authenticatedShow

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can probably do away with this unconventional route, and move everything to the show method. If you retrieve the message before destroying it, it will still be viewable at the time of request, but after refresh will be gone :)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I don't understand how I would handle show and authentication with the same route.

Can you point me in a direction with this? I'm thinking that at a minimum I'll need a get and post endpoint (maybe a third for index which would display the auth form). Get to view the message and post to service an authentication form submission. One of the things I'm uncertain about is what rails expects in terms of convention between endpoints and views. I would think that authentication support would require a distinct view. If the authentication form lives in its own view then does convention demand a corresponding endpoint / controller method?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're doing here. You're flagging the record if they provide a valid password first... which is fine.

One of the things I'm uncertain about is what rails expects in terms of convention between endpoints and views. I would think that authentication support would require a distinct view. If the authentication form lives in its own view then does convention demand a corresponding endpoint / controller method?

In terms of controller methods and view conventions, here is a good reference: http://guides.rubyonrails.org/layouts_and_rendering.html

Basically, your GET methods with map to views with the same name. In ruby, we use snake case method names and file names by default. So your authenticatedShow would become authenticate_show, and even authenticate for brevity. Then you would create a view called authenticate.html.erb which would render by default when hitting the method. Make sense?

Your routes could be simplified to something like:

resources :messages, only :show do
  post 'authenticate', on: :member
end

paramHash = message_params

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to store this off in a new variable. we can just reference strong_params[:password].

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

if @message.password == paramHash[:password] && @message.update(authenticated: true)
redirect_to action: 'show'
else
redirect_to action: 'authenticate'
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_message
@message = Message.find_by message_id: params[:id]
if !@message
redirect_to root_path
end
end

# Never trust parameters from the scary internet, only allow the white list through.
def message_params

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

part of 'the rails way' is sticking to rails convention whenever we can. they have conventionalized a standard filtering of params as strong_params. you can reference this hash later as strong_params[:attribute].

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, are you speaking towards naming as in message_params should be renamed to 'strong_params''?

params.require(:message).permit(:password)
end
end
4 changes: 4 additions & 0 deletions app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "[email protected]"
layout 'mailer'
end
11 changes: 11 additions & 0 deletions app/mailers/message_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class MessageMailer < ApplicationMailer

default from: '[email protected]'

def sd_message(message)
@message = message
@url = 'http://example.com/login'
mail(to: @message.recipient, subject: 'A Message')
end

end
5 changes: 5 additions & 0 deletions app/views/layouts/mailer.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
<%= yield %>
</body>
</html>
1 change: 1 addition & 0 deletions app/views/layouts/mailer.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= yield %>
14 changes: 14 additions & 0 deletions app/views/message_mailer/sd_message.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<h1>A message has been left for you</h1>
<p>
View it here:
<%= url_for(only_path: false, action: 'show', controller: 'recipients', id: @message.message_id) %>.
<br>
</p>
</body>
</html>
2 changes: 1 addition & 1 deletion app/views/messages/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<tbody>
<% @messages.each do |message| %>
<tr>
<td><%= 'TODO: host/messages/' + message.message_id %></td>
<td><%= link_to 'Review message', message %></td>
<td><%= message.recipient %></td>
<td><%= link_to 'Delete Message', message, method: :delete %></td>
</tr>
Expand Down
1 change: 0 additions & 1 deletion app/views/messages/show.json.jbuilder

This file was deleted.

13 changes: 13 additions & 0 deletions app/views/recipients/authenticate.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>Please Authenticate</h1>

<%= form_for(@message, method: 'post', url: '/recipients/' + @message.message_id) do |m| %>

<div class="field">
<%= m.label :password %><br>
<%= m.password_field :password %>
</div>

<div class="actions">
<%= m.submit %>
</div>
<% end %>
6 changes: 6 additions & 0 deletions app/views/recipients/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>This message has been deleted. Once you leave this page it will no longer be available.</h1>

<p>
<strong>Content:</strong>
<%= @message.content %>
</p>
11 changes: 10 additions & 1 deletion config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@
config.action_controller.perform_caching = false

# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:user_name => 'selfdestructmsg',
:password => '$0theRBfly',
:authentication => "plain",
:enable_starttls_auto => true
}

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Rails.application.routes.draw do
resources 'messages', :only => [:index, :new, :create, :show, :destroy]

get 'recipients/:id' => 'recipients#show'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rails can generate RESTful routes automagically for you. Here you would use:

resources :recipients, only: [:show]

and if you wanted to use an unconventional route, you would do:

resources :recipients, only: [:show] do
  get "authenticated" on: :member # gets with an id e.g. recipients/:id/authenticated
  get "authenticated" on: :collection # gets a collection e.g. recipients/authenticated
end

We always want to use RESTful routes when we can. The default rails requests mapped to methods are:

GET: index
GET: show
PUT/PATCH: update
POST: create
DELETE: destroy

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will give this: resources :recipients, only: [:show] a try.

Suppose I could use default routes, though the authentication post would be a bit of a misnomer.

GET: index <-- auth form or redirect to show if auth is not required
GET: show <-- show message
POST: create <-- authenticate

get 'recipients/:id/authenticate' => 'recipients#authenticate'
post 'recipients/:id' => 'recipients#authenticatedShow'

# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
Expand Down
2 changes: 1 addition & 1 deletion db/migrate/20151029052305_create_messages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def change
t.text :recipient
t.text :password
t.text :message_id, :unique => true
t.boolean :viewed
t.boolean :authenticated

t.timestamps null: false
end
Expand Down
6 changes: 3 additions & 3 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
t.text "recipient"
t.text "password"
t.text "message_id"
t.boolean "viewed"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "authenticated"
t.datetime "created_at", null: false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to set null: fase here. Rails will take care of timestamping for you when acting upon your records.

t.datetime "updated_at", null: false
end

end
7 changes: 7 additions & 0 deletions test/controllers/readme_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'test_helper'

class ReadmeControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end
7 changes: 7 additions & 0 deletions test/mailers/message_mailer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'test_helper'

class MessageMailerTest < ActionMailer::TestCase
# test "the truth" do
# assert true
# end
end
4 changes: 4 additions & 0 deletions test/mailers/previews/message_mailer_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Preview all emails at http://localhost:3000/rails/mailers/message_mailer
class MessageMailerPreview < ActionMailer::Preview

end