Commit af139938 by tady

Merge branch 'wip/1230_views'

Conflicts:
	Gemfile.lock
parents 2169521f 80eba16a
service_name: travis-ci
......@@ -17,6 +17,8 @@
/bin/set-env.sh
/config/database.yml
/coverage/.*
*.bk
/db/*.sql
--color
LineLength:
Max: 159
NumericLiterals:
Enabled: false
Documentation:
Enabled: false
WordArray:
Enabled: false
MethodLength:
Max: 30
IfUnlessModifier:
Enabled: false
CyclomaticComplexity:
Max: 10
RaiseArgs:
Enabled: false
language: ruby
services:
- mysql
rvm:
- 2.0.0
before_script:
- mysql -e 'CREATE DATABASE rendezvous_test;'
env:
- DB_TEST_USER=travis
......@@ -6,13 +6,15 @@ ruby '2.0.0'
gem 'rails', '~> 4.0.2'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'
gem 'sass-rails'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
gem 'uglifier'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
gem 'coffee-rails'
gem 'jquery-rails'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
......@@ -24,7 +26,9 @@ gem 'coffee-rails', '~> 4.0.0'
# gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'
gem 'jbuilder'
gem 'i18n_generators'
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
......@@ -45,6 +49,9 @@ end
# gem 'bootstrap-sass-rails'
gem 'mysql2'
gem 'sqlite3'
gem 'devise'
gem 'omniauth-google-oauth2'
......@@ -57,19 +64,39 @@ gem 'coderay'
group :development do
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
gem 'better_errors'
gem 'binding_of_caller'
gem 'thin'
# gem 'capistrano', '~> 3.0.1'
gem 'pry-rails'
# profiler
gem 'rack-mini-profiler'
# rubocop
gem 'rubocop'
gem 'guard-rubocop'
gem 'guard-rspec'
gem 'guard-spring'
gem 'spring'
end
group :production do
gem 'rails_12factor'
gem 'pg'
group :development, :test do
gem 'rspec-rails'
# gem 'database_cleaner'
gem 'database_rewinder'
end
group :test do
gem 'factory_girl_rails'
gem 'capybara'
gem 'launchy'
gem 'poltergeist'
gem 'coveralls', :require => false
end
group :development, :test do
......@@ -79,8 +106,16 @@ end
# tree structure
gem 'ancestry'
# profiler
gem 'rack-mini-profiler'
# Send mail via gmail oauth
# ref. https://github.com/popgiro/action-gmailer
gem 'mail'
gem 'action-gmailer', github: 'popgiro/action-gmailer'
# compose html mail
gem 'nokogiri'
gem 'premailer'
gem 'faraday'
# Google smtp
gem 'gmail_xoauth'
# Check mail format
gem 'validates_email_format_of'
GIT
remote: git://github.com/popgiro/action-gmailer.git
revision: e04b69f578ead4514f6cea5ac85db16896f7e71c
specs:
action-gmailer (0.1.0)
actionmailer
activesupport
gmail_xoauth
GIT
remote: git://github.com/vmg/redcarpet.git
revision: 52c5fa3c5753d2125e827f235cdf4cb730484902
branch: master
......@@ -32,9 +41,11 @@ GEM
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
addressable (2.3.5)
ancestry (2.0.0)
activerecord (>= 3.0.0)
arel (4.0.1)
ast (1.1.0)
atomic (1.1.14)
bcrypt-ruby (3.1.2)
better_errors (1.0.1)
......@@ -43,6 +54,15 @@ GEM
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
builder (3.1.4)
capybara (2.2.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
celluloid (0.15.2)
timers (~> 1.1.0)
cliver (0.3.2)
coderay (1.1.0)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
......@@ -51,7 +71,16 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.6.3)
coveralls (0.7.0)
multi_json (~> 1.3)
rest-client
simplecov (>= 0.7)
term-ansicolor
thor
css_parser (1.3.5)
addressable
daemons (1.1.9)
database_rewinder (0.0.2)
debug_inspector (0.0.2)
devise (3.2.2)
bcrypt-ruby (~> 3.0)
......@@ -60,30 +89,88 @@ GEM
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-lcs (1.2.5)
docile (1.1.1)
domain_name (0.5.15)
unf (>= 0.0.5, < 1.0.0)
erubis (2.7.0)
eventmachine (1.0.3)
execjs (2.0.2)
factory_girl (4.3.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.3.0)
factory_girl (~> 4.3.0)
railties (>= 3.0.0)
faraday (0.8.8)
multipart-post (~> 1.2.0)
ffi (1.9.3)
formatador (0.2.4)
gmail_xoauth (0.4.1)
oauth (>= 0.3.6)
guard (2.2.5)
formatador (>= 0.2.4)
listen (~> 2.1)
lumberjack (~> 1.0)
pry (>= 0.9.12)
thor (>= 0.18.1)
guard-rspec (4.2.3)
guard (~> 2.1)
rspec (>= 2.14, < 4.0)
guard-rubocop (1.0.1)
guard (~> 2.0)
rubocop (~> 0.10)
guard-spring (0.0.4)
guard
spring
hashie (2.0.5)
hike (1.2.3)
htmlentities (4.3.1)
http-cookie (1.0.2)
domain_name (~> 0.5)
httpauth (0.2.0)
i18n (0.6.9)
i18n_generators (1.2.1)
mechanize
rails (>= 3.0.0)
jbuilder (1.5.3)
activesupport (>= 3.0.0)
multi_json (>= 1.2.0)
jquery-rails (3.0.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
jwt (0.1.8)
multi_json (>= 1.5)
launchy (2.4.2)
addressable (~> 2.3)
listen (2.4.0)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.4)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mechanize (2.7.2)
domain_name (~> 0.5, >= 0.5.1)
http-cookie (~> 1.0.0)
mime-types (~> 1.17, >= 1.17.2)
net-http-digest_auth (~> 1.1, >= 1.1.1)
net-http-persistent (~> 2.5, >= 2.5.2)
nokogiri (~> 1.4)
ntlm-http (~> 0.1, >= 0.1.1)
webrobots (>= 0.0.9, < 0.2)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.5.2)
minitest (4.7.5)
multi_json (1.8.2)
multipart-post (1.2.0)
mysql2 (0.3.14)
net-http-digest_auth (1.4)
net-http-persistent (2.9)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
ntlm-http (0.1.1)
oauth (0.4.7)
oauth2 (0.8.1)
faraday (~> 0.8)
......@@ -101,8 +188,25 @@ GEM
oauth2 (~> 0.8.0)
omniauth (~> 1.0)
orm_adapter (0.5.0)
pg (0.17.0)
parser (2.1.2)
ast (~> 1.1)
slop (~> 3.4, >= 3.4.5)
poltergeist (1.5.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
polyglot (0.3.3)
powerpack (0.0.9)
premailer (1.7.9)
css_parser (>= 1.1.9)
htmlentities (>= 4.0.0)
pry (0.9.12.4)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
pry-rails (0.3.2)
pry (>= 0.9.10)
rack (1.5.2)
rack-mini-profiler (0.1.31)
rack (>= 1.1.3)
......@@ -116,19 +220,24 @@ GEM
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.2)
sprockets-rails (~> 2.0.0)
rails_12factor (0.0.2)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.1)
rails_stdout_logging (0.0.3)
railties (4.0.2)
actionpack (= 4.0.2)
activesupport (= 4.0.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (1.99.1)
rake (10.1.0)
rb-fsevent (0.9.4)
rb-inotify (0.9.3)
ffi (>= 0.5.0)
rdoc (3.12.2)
json (~> 1.4)
rest-client (1.6.7)
mime-types (>= 1.16)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.7)
rspec-expectations (2.14.4)
diff-lcs (>= 1.1.3, < 2.0)
......@@ -140,6 +249,10 @@ GEM
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rubocop (0.16.0)
parser (~> 2.1)
powerpack (~> 0.0.6)
rainbow (>= 1.1.4)
sass (3.2.12)
sass-rails (4.0.1)
railties (>= 4.0.0, < 5.0)
......@@ -148,6 +261,13 @@ GEM
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
simplecov (0.8.2)
docile (~> 1.1.0)
multi_json
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
slop (3.4.7)
spring (1.0.0)
sprockets (2.10.1)
hike (~> 1.2)
multi_json (~> 1.0)
......@@ -158,6 +278,8 @@ GEM
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.8)
term-ansicolor (1.2.2)
tins (~> 0.8)
thin (1.6.1)
daemons (>= 1.0.9)
eventmachine (>= 1.0.0)
......@@ -166,6 +288,8 @@ GEM
thread_safe (0.1.3)
atomic
tilt (1.4.1)
timers (1.1.0)
tins (0.13.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
......@@ -173,30 +297,56 @@ GEM
uglifier (2.3.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.3)
unf_ext
unf_ext (0.0.6)
validates_email_format_of (1.5.3)
warden (1.2.3)
rack (>= 1.0)
webrobots (0.1.1)
websocket-driver (0.3.2)
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
action-gmailer!
ancestry
better_errors
binding_of_caller
capybara
coderay
coffee-rails (~> 4.0.0)
coffee-rails
coveralls
database_rewinder
devise
gmail_xoauth
jbuilder (~> 1.2)
factory_girl_rails
faraday
guard-rspec
guard-rubocop
guard-spring
i18n_generators
jbuilder
jquery-rails
launchy
mail
mysql2
nokogiri
omniauth-google-oauth2
pg
poltergeist
premailer
pry-rails
rack-mini-profiler
rails (~> 4.0.2)
rails_12factor
redcarpet!
rspec-rails
sass-rails (~> 4.0.0)
rubocop
sass-rails
sdoc
spring
sqlite3
thin
uglifier (>= 1.3.0)
uglifier
validates_email_format_of
guard :rspec, all_after_pass: true, spring: true do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { 'spec' }
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { 'spec/features' }
watch(%r{^spec/factories/(.+)\.rb$}) { 'spec/factories_spec.rb' }
watch(%r{^spec/support/(.+)\.rb$}) { 'spec' }
watch('config/routes.rb') { 'spec/routing' }
watch('app/controllers/application_controller.rb') { 'spec/controllers' }
end
guard :rubocop, all_after_pass: true, cli: ['--rails', '--auto-correct'] do
watch(%r{.+\.rb$})
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end
rendezvous
==========
## Badge
[![Build Status](https://travis-ci.org/tadyjp/rendezvous.png)](https://travis-ci.org/tadyjp/rendezvous)
[![Coverage Status](https://coveralls.io/repos/tadyjp/rendezvous/badge.png)](https://coveralls.io/r/tadyjp/rendezvous)
[![Code Climate](https://codeclimate.com/github/tadyjp/rendezvous.png)](https://codeclimate.com/github/tadyjp/rendezvous)
[![Dependency Status](https://gemnasium.com/tadyjp/rendezvous.png)](https://gemnasium.com/tadyjp/rendezvous)
## ENVの設定
```
......
......@@ -12,7 +12,7 @@
//
//= require_self
// require jquery
// require jquery_ujs
//= require jquery_ujs
// require turbolinks
//= require_tree ./lib
//= require_tree .
......
if window.location.pathname.match /^\/$/
if window.location.pathname.match /^\/posts\/?$/
$ ->
......@@ -11,22 +11,32 @@ if window.location.pathname.match /^\/$/
$this.addClass('active')
id = $this.data('postId')
$.get('/posts/show_fragment', { id: id })
$.get("/posts/#{id}", {
fragment: 1
})
.done (data) ->
$('#list_post').html(data)
prettyPrint()
# 初期に詳細を表示
# open post when `id` parameter set.
id_param = RV.tools.getQueryParams()["id"]
if id_param?
$(".post-list[data-post-id='#{id_param}']").addClass('active')
$.get('/posts/show_fragment', {
'id': id_param,
$("a.post-list[data-post-id='#{id_param}']").addClass('active')
$.get("/posts/#{id_param}", {
fragment: 1
})
.done (data) ->
$('#list_post').html(data)
prettyPrint()
else
$el = $("a.post-list:eq(0)")
$el.addClass('active')
$.get("/posts/#{$el.data('postId')}", {
fragment: 1
})
.done (data) ->
$('#list_post').html(data)
prettyPrint()
......@@ -4,8 +4,6 @@
.app {
padding-top: 70px;
.navbar-default .navbar-brand {
background-color: #428bca;
color: #fff;
......@@ -51,6 +49,12 @@
width: 200px;
}
/* side tree view
-------------------------------------------------- */
ul {
padding-left: 1em;
}
/* home#show
-------------------------------------------------- */
.text-box {
......
body[class^="posts-"] {
padding-top: 70px;
}
.treeview, .treeview ul {
padding: 0;
margin: 0;
list-style: none;
}
.treeview ul {
background-color: white;
margin-top: 4px;
}
.treeview .hitarea {
background: url(images/treeview-default.gif) -64px -25px no-repeat;
height: 16px;
width: 16px;
margin-left: -16px;
float: left;
cursor: pointer;
}
/* fix for IE6 */
* html .hitarea {
display: inline;
float:none;
}
.treeview li {
margin: 0;
padding: 3px 0pt 3px 16px;
}
.treeview a.selected {
background-color: #eee;
}
#treecontrol { margin: 1em 0; display: none; }
.treeview .hover { color: red; cursor: pointer; }
.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
.treeview .expandable-hitarea { background-position: -80px -3px; }
.treeview li.last { background-position: 0 -1766px }
.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); }
.treeview li.lastCollapsable { background-position: 0 -111px }
.treeview li.lastExpandable { background-position: -32px -67px }
.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
.treeview-red li { background-image: url(images/treeview-red-line.gif); }
.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); }
.treeview-black li { background-image: url(images/treeview-black-line.gif); }
.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); }
.treeview-gray li { background-image: url(images/treeview-gray-line.gif); }
.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); }
.treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); }
.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); }
.treeview .placeholder {
background: url(images/ajax-loader.gif) 0 0 no-repeat;
height: 16px;
width: 16px;
display: block;
}
.filetree li { padding: 3px 0 2px 16px; }
.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; }
.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }
.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; }
......@@ -3,7 +3,6 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def require_login
unless user_signed_in?
flash[:alert] = 'You need Login!'
......@@ -11,4 +10,7 @@ class ApplicationController < ActionController::Base
end
end
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
render text: "Required parameter missing: #{parameter_missing_exception.param}", status: :bad_request
end
end
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="initial-scale=1.0"> <!-- So that mobile webkit will display zoomed in -->
<meta name="format-detection" content="telephone=no"> <!-- disable auto telephone linking in iOS -->
<title>2 columns to rows template | Antwort</title>
<style type="text/css">
/* Resets: see reset.css for details */
.ReadMsgBody { width: 100%; background-color: #ebebeb;}
.ExternalClass {width: 100%; background-color: #ebebeb;}
.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height:100%;}
body {-webkit-text-size-adjust:none; -ms-text-size-adjust:none;}
body {margin:0; padding:0;}
table {border-spacing:0;}
table td {border-collapse:collapse;}
.yshortcuts a {border-bottom: none !important;}
/* Constrain email width for small screens */
@media screen and (max-width: 600px) {
table[class="container"] {
width: 95% !important;
}
}
/* Give content more room on mobile */
@media screen and (max-width: 480px) {
td[class="container-padding"] {
padding-left: 12px !important;
padding-right: 12px !important;
}
}
/* Styles for forcing columns to rows */
@media only screen and (max-width : 600px) {
/* force container columns to (horizontal) blocks */
td[class="force-col"] {
display: block;
padding-right: 0 !important;
}
table[class="col-2"] {
/* unset table align="left/right" */
float: none !important;
width: 100% !important;
/* change left/right padding and margins to top/bottom ones */
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid #eee;
}
/* remove bottom border for last column/row */
table[id="last-col-2"] {
border-bottom: none !important;
margin-bottom: 0;
}
/* align images right and shrink them a bit */
img[class="col-2-img"] {
float: right;
margin-left: 6px;
max-width: 130px;
}
}
.viewer.github a {
color: #4183C4; }
.viewer.github a.absent {
color: #cc0000; }
.viewer.github a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
.viewer.github h1, .viewer.github h2, .viewer.github h3, .viewer.github h4, .viewer.github h5, .viewer.github h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
.viewer.github h1:hover a.anchor, .viewer.github h2:hover a.anchor, .viewer.github h3:hover a.anchor, .viewer.github h4:hover a.anchor, .viewer.github h5:hover a.anchor, .viewer.github h6:hover a.anchor {
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
text-decoration: none; }
.viewer.github h1 tt, .viewer.github h1 code {
font-size: inherit; }
.viewer.github h2 tt, .viewer.github h2 code {
font-size: inherit; }
.viewer.github h3 tt, .viewer.github h3 code {
font-size: inherit; }
.viewer.github h4 tt, .viewer.github h4 code {
font-size: inherit; }
.viewer.github h5 tt, .viewer.github h5 code {
font-size: inherit; }
.viewer.github h6 tt, .viewer.github h6 code {
font-size: inherit; }
.viewer.github h1 {
font-size: 28px;
color: black; }
.viewer.github h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }
.viewer.github h3 {
font-size: 18px; }
.viewer.github h4 {
font-size: 16px; }
.viewer.github h5 {
font-size: 14px; }
.viewer.github h6 {
color: #777777;
font-size: 14px; }
.viewer.github p, .viewer.github blockquote, .viewer.github ul, .viewer.github ol, .viewer.github dl, .viewer.github li, .viewer.github table, .viewer.github pre {
margin: 15px 0; }
.viewer.github hr {
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0; }
.viewer.github body > h2:first-child {
margin-top: 0;
padding-top: 0; }
.viewer.github body > h1:first-child {
margin-top: 0;
padding-top: 0; }
.viewer.github body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
.viewer.github body > h3:first-child, .viewer.github body > h4:first-child, .viewer.github body > h5:first-child, .viewer.github body > h6:first-child {
margin-top: 0;
padding-top: 0; }
.viewer.github a:first-child h1, .viewer.github a:first-child h2, .viewer.github a:first-child h3, .viewer.github a:first-child h4, .viewer.github a:first-child h5, .viewer.github a:first-child h6 {
margin-top: 0;
padding-top: 0; }
.viewer.github h1 p, .viewer.github h2 p, .viewer.github h3 p, .viewer.github h4 p, .viewer.github h5 p, .viewer.github h6 p {
margin-top: 0; }
.viewer.github li p.first {
display: inline-block; }
.viewer.github ul, .viewer.github ol {
padding-left: 30px; }
.viewer.github ul :first-child, .viewer.github ol :first-child {
margin-top: 0; }
.viewer.github ul :last-child, .viewer.github ol :last-child {
margin-bottom: 0; }
.viewer.github dl {
padding: 0; }
.viewer.github dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
.viewer.github dl dt:first-child {
padding: 0; }
.viewer.github dl dt > :first-child {
margin-top: 0; }
.viewer.github dl dt > :last-child {
margin-bottom: 0; }
.viewer.github dl dd {
margin: 0 0 15px;
padding: 0 15px; }
.viewer.github dl dd > :first-child {
margin-top: 0; }
.viewer.github dl dd > :last-child {
margin-bottom: 0; }
.viewer.github blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
.viewer.github blockquote > :first-child {
margin-top: 0; }
.viewer.github blockquote > :last-child {
margin-bottom: 0; }
.viewer.github table {
padding: 0; }
.viewer.github table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.viewer.github table tr:nth-child(2n) {
background-color: #f8f8f8; }
.viewer.github table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
.viewer.github table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
.viewer.github table tr th :first-child, .viewer.github table tr td :first-child {
margin-top: 0; }
.viewer.github table tr th :last-child, .viewer.github table tr td :last-child {
margin-bottom: 0; }
.viewer.github img {
max-width: 100%; }
.viewer.github span.frame {
display: block;
overflow: hidden; }
.viewer.github span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
.viewer.github span.frame span img {
display: block;
float: left; }
.viewer.github span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
.viewer.github span.align-center {
display: block;
overflow: hidden;
clear: both; }
.viewer.github span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
.viewer.github span.align-center span img {
margin: 0 auto;
text-align: center; }
.viewer.github span.align-right {
display: block;
overflow: hidden;
clear: both; }
.viewer.github span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
.viewer.github span.align-right span img {
margin: 0;
text-align: right; }
.viewer.github span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
.viewer.github span.float-left span {
margin: 13px 0 0; }
.viewer.github span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
.viewer.github span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }
.viewer.github code, .viewer.github tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }
.viewer.github pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }
.viewer.github .highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
.viewer.github pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
.viewer.github pre code, .viewer.github pre tt {
background-color: transparent;
border: none; }
</style>
</head>
<body style="margin:0; padding:10px 0;" bgcolor="#ebebeb" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<br>
<!-- 100% wrapper (grey background) -->
<table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#ebebeb">
<tr>
<td align="center" valign="top" bgcolor="#ebebeb" style="background-color: #ebebeb;">
<!-- 600px container (white background) -->
<table border="0" width="600" cellpadding="0" cellspacing="0" class="container" bgcolor="#ffffff">
<tr>
<td class="container-padding" bgcolor="#ffffff" style="background-color: #ffffff; padding-left: 30px; padding-right: 30px; font-size: 14px; line-height: 20px; font-family: Helvetica, sans-serif; color: #333;">
<br>
__HTML_BODY__
<br>
</td>
</tr>
<tr>
<td class="container-padding" bgcolor="#ffffff" style="background-color: #ffffff; padding-left: 30px; padding-right: 30px; font-size: 13px; line-height: 20px; font-family: Helvetica, sans-serif; color: #333;" align="left">
<br>
<hr>
このメールは<a href="#">Rendezvous</a>から送信されています。
<br><br>
</td>
</tr>
</table>
<!--/600px container -->
</td>
</tr>
</table>
<!--/100% wrapper-->
<br>
<br>
</body>
</html>
require 'mail'
require 'action_gmailer'
require 'premailer'
module RV::Mailer
include ApplicationHelper
def compose_mail(post, opts = {})
fail ArgumentError.new('post missing') unless post.present?
fail ArgumentError.new('user missing') unless opts[:user].present? && opts[:user].is_a?(User)
fail ArgumentError.new('to missing') unless opts[:to].present?
fail ArgumentError.new('to mail format invalid') unless ValidatesEmailFormatOf.validate_email_format(opts[:to]).nil?
html_body = generate_html_mail(post.body)
mail = Mail.new do
from opts[:user].email
to opts[:to]
subject post.title
body post.body
html_part do
content_type 'text/html; charset=UTF-8'
body html_body
end
end
# set ActionGmailer
config = {
oauth2_token: opts[:user].google_auth_token,
account: opts[:user].email
}.merge(Rendezvous::Application.config.action_mailer.smtp_settings)
mail.delivery_method(ActionGmailer::DeliveryMethod, config)
mail
end
def generate_html_mail(body)
path = File.expand_path(File.dirname(__FILE__) + '/mail-template.html')
template = File.open(path).read
html_body = template.sub('__HTML_BODY__', h_application_format_markdown(body))
premailer = Premailer.new(html_body, with_html_string: true, adapter: :nokogiri)
premailer.to_inline_css
end
end
class HomeController < ApplicationController
skip_before_action :require_login
def show
def top
if user_signed_in?
redirect_to posts_path, status: 301
else
render template: 'home/login'
end
end
end
require 'nkf'
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :require_login, except: [:index]
before_action :require_login
include ApplicationHelper
include RV::Mailer
# GET /posts
# GET /posts.json
def index
if user_signed_in?
if params[:q].present?
@posts = Post.build_query(params).limit(10)
@posts = Post.search(params[:q]).limit(10)
else
@posts = Post.order(updated_at: :desc).limit(10)
end
render
else
render file: 'home/login'
end
end
def preview
render text: h_application_format_markdown(params[:text])
end
def show_fragment
@post = Post.find(params[:id])
render layout: false, partial: 'posts/show_fragment'
end
# GET /posts/1
# GET /posts/1.json
def show
if params[:fragment].present?
render layout: false, partial: 'posts/show_fragment'
else
render
end
end
# GET /posts/new
......@@ -45,32 +37,22 @@ class PostsController < ApplicationController
end
def fork
@post = set_post.clone
@post.title = @post.title.gsub(/%Name/, current_user.name)
@post.title = Time.now.strftime(@post.title) # TODO
@post = set_post.generate_fork(current_user)
render action: 'new'
end
def mail
@post = set_post
smtp = Net::SMTP.new('smtp.gmail.com', 587)
smtp.enable_starttls_auto
smtp.start('gmail.com', current_user.email, current_user.google_auth_token, :xoauth2)
body = 'test'
body = <<EOT
From: #{current_user.email}
To: #{current_user.email}
Subject: #{NKF.nkf("-WjMm0", 'subject')}
Date: #{Time::now.strftime("%a, %d %b %Y %X %z")}
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
#{NKF.nkf("-Wjm0", body)}
EOT
smtp.send_mail body, current_user.email, current_user.email
smtp.finish
redirect_to root_path(id: @post.id)
# refresh google oauth token if expired
current_user.google_oauth_token_refresh! if current_user.google_oauth_token_expired?
compose_mail(@post, user: current_user, to: mail_params[:to]).deliver
redirect_to root_path(id: @post.id), flash: { success: 'Mail has sent!' }
rescue ActionGmailer::DeliveryError
redirect_to root_path(id: @post.id), flash: { notice: 'Gmail authentication expired.' }
rescue ArgumentError => err
redirect_to root_path(id: @post.id), flash: { alert: 'Mail format is invalid: ' + err.to_s }
end
# GET /posts/1/edit
......@@ -85,7 +67,7 @@ EOT
respond_to do |format|
if @post.save
format.html { redirect_to root_path(id: @post.id), notice: 'Post was successfully created.' }
format.html { redirect_to root_path(id: @post.id), flash: { notice: 'Post was successfully created.' } }
format.json { render action: 'show', status: :created, location: @post }
else
format.html { render action: 'new' }
......@@ -101,7 +83,7 @@ EOT
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to root_path(id: @post.id), notice: 'Post was successfully updated.' }
format.html { redirect_to root_path(id: @post.id), flash: { notice: 'Post was successfully updated.' } }
format.json { head :no_content }
else
format.html { render action: 'edit' }
......@@ -115,12 +97,13 @@ EOT
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.html { redirect_to posts_url, flash: { success: 'Post successfully deleted.' } }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
......@@ -137,9 +120,13 @@ EOT
tags = tags_text.split(',').map do |_tag_name|
Tag.find_or_create_by(name: _tag_name)
end
_param_hash["tag_ids"] = tags.map(&:id)
_param_hash['tag_ids'] = tags.map(&:id)
_param_hash
end
end
def mail_params
params.require(:mail).permit(:to).to_hash.symbolize_keys
end
end
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
# You need to implement the method below in your model (e.g. app/models/user.rb)
@user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
@user = User.find_for_google_oauth2(request.env['omniauth.auth'], current_user)
if @user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
sign_in_and_redirect @user, :event => :authentication
flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
sign_in_and_redirect @user, event: :authentication
else
session["devise.google_data"] = request.env["omniauth.auth"]
session['devise.google_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end
module ApplicationHelper
class HtmlWithPrettyPrint < Redcarpet::Render::HTML
def postprocess(full_document)
full_document.gsub("prettyprint", "prettyprint linenums")
full_document.gsub('prettyprint', 'prettyprint linenums')
end
end
def h_application_format_markdown(text)
# html_render = HTMLwithCoderay.new(filter_html: true, hard_wrap: true, prettify: true)
html_render = HtmlWithPrettyPrint.new(:prettify => true)
html_render = HtmlWithPrettyPrint.new(prettify: true)
options = {
autolink: true,
space_after_headers: true,
......@@ -18,5 +17,4 @@ module ApplicationHelper
markdown = Redcarpet::Markdown.new(html_render, options)
markdown.render(text).html_safe
end
end
module PostsHelper
# @param {ActiveRecord::Relation} node
def h_display_tree(node)
_html = '<ul>'
if node.posts.count > 0
_html << %Q{<li><a href="#{ root_path(q: '#' + node.name) }">#{node.name} <span class="badge">#{node.posts.count}</span></a></li>}
_html << %Q{<li><a href="#{ posts_path(q: '#' + node.name) }">#{node.name} <span class="badge">#{node.posts.count}</span></a></li>}
end
node.children.each do |_child|
_html << h_display_tree(_child)
end
_html << '</ul>'
_html.html_safe
end
end
module StyleHelper
## Store style
# Usage:
# <% style do %>
# div {
# color: red;
# }
# <% end %>
def style(&block)
content_for(content_key, capture(&block))
end
## Render all style
def render_style
return if content_for(content_key).nil?
html_buf = '<style type="text/css">'
html_buf << content_for(content_key)
html_buf << '</style>'
html_buf.html_safe
end
private
# Use for `content_for`
def content_key
:style_addon
end
end
......@@ -4,29 +4,26 @@ class Post < ActiveRecord::Base
belongs_to :author, class_name: 'User'
# Named scope
scope :search, (lambda do |query|
_where_list = includes(:author, :tags)
def self.build_query(params)
_where_list = self.includes(:author, :tags)
# 空白を一つに変換
query_string = params[:q].gsub(/[\s ]+/, ' ')
query_list = query_string.split(' ')
# Convert spaces to one space.
query_list = query.gsub(/[\s ]+/, ' ').split(' ')
query_list.each do |_query|
case _query
when /^post:(.+)/
_where_list = _where_list.where('id = ?', $1)
when /^id:(.+)/
_where_list = _where_list.where(id: Regexp.last_match[1])
when /^title:(.+)/
_where_list = _where_list.where('title LIKE ?', "%#{$1}%")
_where_list = _where_list.where('title LIKE ?', "%#{Regexp.last_match[1]}%")
when /^body:(.+)/
_where_list = _where_list.where('body LIKE ?', "%#{$1}%")
_where_list = _where_list.where('body LIKE ?', "%#{Regexp.last_match[1]}%")
when /^@(.+)/
_where_list = _where_list.where('users.name = ?', $1)
_where_list = _where_list.where(users: { name: Regexp.last_match[1] })
when /^#(.+)/
_where_list = _where_list.where('tags.name = ?', $1)
_where_list = _where_list.where(tags: { name: Regexp.last_match[1] })
when /^date:(\d+)-(\d+)-(\d+)/
_date = Time.new($1, $2, $3)
_date = Time.new(Regexp.last_match[1], Regexp.last_match[2], Regexp.last_match[3])
_where_list = _where_list.where('updated_at > ? AND updated_at < ?', _date, _date + 1.day)
else
_where_list = _where_list.where('title LIKE ? OR body LIKE ?', "%#{_query}%", "%#{_query}%")
......@@ -34,7 +31,15 @@ class Post < ActiveRecord::Base
end
_where_list
end)
end
# generate forked post (not saved)
def generate_fork(user)
forked_post = clone
forked_post.title = forked_post.title.gsub(/%Name/, user.name)
forked_post.title = Time.now.strftime(forked_post.title) # TODO
forked_post.author = user
forked_post
end
end
......@@ -3,5 +3,4 @@ class Tag < ActiveRecord::Base
has_many :posts, through: :post_tags
has_ancestry
end
require 'faraday'
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
devise :omniauthable, :omniauth_providers => [:google_oauth2]
devise :omniauthable, omniauth_providers: [:google_oauth2]
has_many :posts
# Device
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
def self.find_for_google_oauth2(access_token, signed_in_resource = nil)
data = access_token.info
user = User.where(:email => data["email"]).first
user = User.where(email: data['email']).first
unless user
user = User.create(name: data["name"],
image_url: data["image"],
email: data["email"],
password: Devise.friendly_token[0,20]
user = User.create(name: data['name'],
image_url: data['image'],
email: data['email'],
password: Devise.friendly_token[0, 20]
)
end
user.update_attribute(:google_auth_token, access_token.credentials['token'])
user.update_attributes(
google_auth_token: access_token.credentials['token'],
google_refresh_token: access_token.credentials['refresh_token'],
google_token_expires_at: Time.at(access_token.credentials['expires_at'])
)
user
end
# check if google oauth token is expired
def google_oauth_token_expired?
google_token_expires_at < Time.now
end
# refresh google oauth token
def google_oauth_token_refresh!
conn = Faraday.new(url: 'https://accounts.google.com') do |builder|
builder.request :url_encoded
builder.adapter :net_http
end
response = conn.post '/o/oauth2/token',
client_id: ENV['GOOGLE_KEY'],
client_secret: ENV['GOOGLE_SECRET'],
refresh_token: google_refresh_token,
grant_type: 'refresh_token'
res_json = JSON.parse(response.body)
update_attributes(
google_auth_token: res_json['access_token'],
google_token_expires_at: Time.now + res_json['expires_in'].seconds
)
end
end
......@@ -9,23 +9,13 @@
<!-- Optional theme -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap-theme.min.css">
<%= render_style %>
<%= csrf_meta_tags %>
</head>
<body>
<body class="<%= params[:controller] %>-<%= params[:action] %>">
<% if notice %>
<script type="text/javascript">
alert('<%= notice %>');
</script>
<!-- <p class="notice"><%= notice %></p> -->
<% end %>
<% if alert %>
<script type="text/javascript">
alert('<%= alert %>');
</script>
<!-- <p class="notice"><%= notice %></p> -->
<p class="alert"><%= alert %></p>
<% end %>
<%= render partial: 'partials/header_notifications' %>
<%= yield %>
......
......@@ -14,17 +14,21 @@
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form id="app-search-form" class="navbar-form navbar-left" role="search" action="<%= root_path %>">
<form id="app-search-form" class="navbar-form navbar-left" role="search" action="<%= posts_path %>">
<div class="input-group">
<input type="text" name="q" class="form-control" value="<%= params[:q] %>" placeholder="Search">
<span class="input-group-btn">
<button type="submit" class="btn btn-default">
<button type="submit" class="btn btn-default" data-disable-with="Searching...">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</form>
<p class="navbar-text" id="header-search-hint">
<a href="#"><span class="glyphicon glyphicon-question-sign" data-toggle="modal" data-target="#header-search-description"></span></a>
</p>
<%= form_tag(destroy_user_session_path, :method => :delete, class: 'navbar-form navbar-right') do %>
<%= submit_tag 'SignOut', class: 'btn btn-default' %>
<% end %>
......@@ -41,3 +45,42 @@
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
<!-- Modal #header-search-description -->
<div class="modal fade" id="header-search-description" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel">Search command</h4>
</div>
<div class="modal-body">
<dl class="dl-horizontal">
<dt>Search by title</dt>
<dd><pre><a href="<%= posts_path(q: 'title:ruby') %>">title:ruby</a></pre></dd>
<dt>Search by id</dt>
<dd><pre><a href="<%= posts_path(q: 'id:123') %>">id:123</a></pre></dd>
<dt>Search by body</dt>
<dd><pre><a href="<%= posts_path(q: 'body:ruby') %>">body:ruby</a></pre></dd>
<dt>Search by author</dt>
<dd><pre><a href="<%= posts_path(q: '@taro') %>">@taro</a></pre></dd>
<dt>Search by tag</dt>
<dd><pre><a href="<%= posts_path(q: '#ruby') %>">#ruby</a></pre></dd>
<dt>Search by date</dt>
<dd><pre><a href="<%= posts_path(q: 'date:2013-12-16') %>">date:2013-12-16</a></pre></dd>
<dt>Search by title or body</dt>
<dd><pre><a href="<%= posts_path(q: 'ruby') %>">ruby</a></pre></dd>
</dl>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<% style do %>
#header-search-hint{
margin-left: 0;
}
<% end %>
<% if flash[:success] %>
<div class="alert alert-success fade in">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Success</strong> <%= flash[:success] %>
</div>
<% end %>
<% if flash[:notice] %>
<div class="alert alert-warning fade in">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Notice</strong> <%= flash[:notice] %>
</div>
<% end %>
<% if flash[:alert] %>
<div class="alert alert-danger fade in">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Alert</strong> <%= flash[:alert] %>
</div>
<% end %>
<div style="text-align:right">
<a href="<%= mail_post_path(@post) %>" class="btn navbar-btn" style!="position:absolute;right:0;top:0;margin-top:2px;margin-top:3px;margin-right:3px;">
Mail
</a>
<a href="<%= fork_post_path(@post) %>" class="btn navbar-btn" style!="position:absolute;right:0;top:0;margin-top:2px;margin-top:3px;margin-right:3px;">
Fork
</a>
<a href="<%= edit_post_path(@post) %>" class="btn btn-primary navbar-btn" style!="position:absolute;right:0;top:0;margin-top:2px;margin-top:3px;margin-right:3px;">
<span class="glyphicon glyphicon-pencil"></span>
</a>
</div>
<div class="text-box title" style!="position:relative;">
<a href="<%= post_path(@post) %>"><%= @post.title %></a>
</div>
<div class="text-box meta">
<% @post.tags.each do |tag| %>
<span class="label label-info">
<a href="<%= root_path(q: "##{tag.name}") %>">#<%= tag.name %></a>
<a href="<%= posts_path(q: "##{tag.name}") %>">#<%= tag.name %></a>
</span>
<% end %>
<span class="label label-success">
<a href="<%= root_path(q: "@#{@post.author.name}") %>">@<%= @post.author.name %></a>
<a href="<%= posts_path(q: "@#{@post.author.name}") %>">@<%= @post.author.name %></a>
</span>
<span class="label label-danger">
<a href="<%= root_path(q: "date:#{@post.updated_at.strftime('%Y-%m-%d')}") %>"><%= @post.updated_at.strftime('%Y-%m-%d') %></a>
<a href="<%= posts_path(q: "date:#{@post.updated_at.strftime('%Y-%m-%d')}") %>"><%= @post.updated_at.strftime('%Y-%m-%d') %></a>
</span>
<!-- Split button -->
<div class="btn-group pull-right" style="margin: -7px -12px 0 0;">
<button type="button" class="btn btn-primary">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="<%= fork_post_path(@post) %>">Fork</a></li>
<li><a href="#" data-toggle="modal" data-target="#myModal">Mail to...</a></li>
<li class="divider"></li>
<li><%= link_to 'Delete', post_path(@post), method: :delete, data: { confirm: 'Are you sure?' } %></li>
</ul>
</div>
<!-- /Split button -->
</div>
<div class="text-box body viewer github">
<%= h_application_format_markdown(@post.body) %>
</div>
<!-- Button trigger modal -->
<!-- <button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
-->
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<%= form_tag mail_post_path(@post), method: :post, class: 'form-horizontal', role: 'form' do %>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel">Mail this post to...</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label class="col-sm-2 control-label">Title</label>
<div class="col-sm-10">
<input type="text" class="form-control" value="<%= @post.title %>" readonly>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">To</label>
<div class="col-sm-10">
<input type="email" name="mail[to]" class="form-control" id="inputEmail3" placeholder="Email">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">From</label>
<div class="col-sm-10">
<input type="text" class="form-control" value="<%= current_user.email %>" readonly>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" data-disable-with="Sending...">Send</button>
</div>
</div><!-- /.modal-content -->
<% end %><%# form %>
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
......@@ -9,12 +9,20 @@
<div class="col-xs-6 col-md-4" id="sidebar" role="navigation">
<ul class="nav nav-tabs">
<li class="active"><a href="#tab-list" data-toggle="tab">List</a></li>
<li><a href="#tab-tree" data-toggle="tab">Tag Tree</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab-list">
<div class="list-group">
<% @posts.each do |post| %>
<% @posts.each_with_index do |post, i| %>
<a href="#" data-post-id="<%= post.id %>" class="list-group-item post-list"><%= post.title %></a>
<% end %>
</div>
</div><!-- /.tab-pane -->
<div class="tab-pane" id="tab-tree">
<% cache('tag-tree', :expires_in => 1.hour) do %>
<div class="list-group">
<% Tag.roots.each do |root| %>
......@@ -22,13 +30,15 @@
<% end %>
</div>
<% end %>
</div><!-- /.tab-pane -->
</div><!-- /.tab-content -->
</div><!--/span-->
<div class="col-xs-12 col-sm-6 col-md-8">
<div id="list_post">
<p style="color:#aaa;font-size:30px">&lt;-- Select a post...</p>
<p id="posts-placeholder" style="color:#aaa;font-size:30px">&lt;-- Select a post...</p>
</div>
</div><!--/span-->
......@@ -38,6 +48,9 @@
<hr>
<footer>
<a href="https://github.com/tadyjp/rendezvous">Github</a>
|
<a href="https://twitter.com/tady_jp">@tady_jp</a>
</footer>
</div><!--/.container-->
......
......@@ -6,22 +6,13 @@
<div class="container">
<div class="row">
<div class="col-xs-12 col-md-12">
<div id="xxxxxxxx">
<%= render partial: 'posts/show_fragment' %>
</div>
</div><!--/span-->
</div><!--/row-->
<hr>
<footer>
</footer>
</div><!--/.container-->
</div>
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'spring' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('spring', 'spring')
#! /usr/bin/env python
import sys
def main():
print "SET sql_mode='NO_BACKSLASH_ESCAPES';"
lines = sys.stdin.read().splitlines()
for line in lines:
processLine(line)
def processLine(line):
if (
line.startswith("PRAGMA") or
line.startswith("BEGIN TRANSACTION;") or
line.startswith("COMMIT;") or
line.startswith("DELETE FROM sqlite_sequence;") or
line.startswith("INSERT INTO \"sqlite_sequence\"")
):
return
line = line.replace("AUTOINCREMENT", "AUTO_INCREMENT")
line = line.replace("DEFAULT 't'", "DEFAULT '1'")
line = line.replace("DEFAULT 'f'", "DEFAULT '0'")
line = line.replace(",'t'", ",'1'")
line = line.replace(",'f'", ",'0'")
in_string = False
newLine = ''
for c in line:
if not in_string:
if c == "'":
in_string = True
elif c == '"':
newLine = newLine + '`'
continue
elif c == "'":
in_string = False
newLine = newLine + c
print newLine
if __name__ == "__main__":
main()
......@@ -20,6 +20,17 @@ module Rendezvous
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
I18n.enforce_available_locales = true
config.i18n.default_locale = 'ja'
# config.action_mailer.delivery_method = :action_gmailer
config.action_mailer.smtp_settings = {
smtp_host: 'smtp.gmail.com',
smtp_port: 587,
helo_domain: 'gmail.com',
auth_type: :xoauth2,
# oauth2_token: 'FIXME',
# account: 'FIXME'
}
end
end
......@@ -4,19 +4,32 @@
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
development:
adapter: sqlite3
database: db/development.sqlite3
adapter: mysql2
encoding: utf8
reconnect: false
database: <%= ENV['DB_DEVELOPMENT_DATABASE'] %>
pool: 5
timeout: 5000
username: <%= ENV['DB_DEVELOPMENT_USER'] %>
password: <%= ENV['DB_DEVELOPMENT_PASS'] %>
host: <%= ENV['DB_DEVELOPMENT_HOST'] %>
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
# test:
# adapter: sqlite3
# database: db/test.sqlite3
# pool: 5
# timeout: 5000
test:
adapter: sqlite3
database: db/test.sqlite3
adapter: mysql2
encoding: utf8
reconnect: false
database: <%= ENV['DB_TEST_DATABASE'] %>
pool: 5
timeout: 5000
username: <%= ENV['DB_TEST_USER'] %>
password: <%= ENV['DB_TEST_PASS'] %>
host: <%= ENV['DB_TEST_HOST'] %>
production:
adapter: sqlite3
......
......@@ -28,5 +28,5 @@ Rendezvous::Application.configure do
config.assets.debug = true
# Devise
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.default_url_options = { host: 'localhost:3000' }
end
......@@ -14,7 +14,7 @@ Rendezvous::Application.configure do
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
......
......@@ -41,12 +41,12 @@ Devise.setup do |config|
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
config.case_insensitive_keys = [ :email ]
config.case_insensitive_keys = [:email]
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email.
config.strip_whitespace_keys = [ :email ]
config.strip_whitespace_keys = [:email]
# Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the
......
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"],
{
:name => "google_oauth2",
:scope => "https://mail.google.com/, userinfo.email, userinfo.profile",
:prompt => "select_account",
:image_aspect_ratio => "square",
:image_size => 50
}
provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'],
name: 'google_oauth2',
scope: 'https://mail.google.com/, userinfo.email, userinfo.profile',
access_type: 'offline',
prompt: 'select_account consent',
image_aspect_ratio: 'square',
image_size: 50
end
......@@ -9,4 +9,5 @@
# Make sure your secret_key_base is kept private
# if you're sharing your code publicly.
Rendezvous::Application.config.secret_key_base = 'd8e487b60856000161a94ea764b38e7492512bbbeeca2f4cec068c8cc6618cacb54172ec54afc61675684f01bf02c74bf1e93dfe6971247d75ff001b1584d987'
Rendezvous::Application.config.secret_key_base = \
'd8e487b60856000161a94ea764b38e7492512bbbeeca2f4cec068c8cc6618cacb54172ec54afc61675684f01bf02c74bf1e93dfe6971247d75ff001b1584d987'
# Be sure to restart your server when you modify this file.
Rendezvous::Application.config.session_store :cookie_store, key: '_rendezvous_session'
Rendezvous::Application.config.session_store :cookie_store,
key: '__rv__'
ja:
date:
abbr_day_names:
-
-
-
-
-
-
-
abbr_month_names:
-
- 1月
- 2月
- 3月
- 4月
- 5月
- 6月
- 7月
- 8月
- 9月
- 10月
- 11月
- 12月
day_names:
- 日曜日
- 月曜日
- 火曜日
- 水曜日
- 木曜日
- 金曜日
- 土曜日
formats:
default: ! '%Y/%m/%d'
long: ! '%Y年%m月%d日(%a)'
short: ! '%m/%d'
month_names:
-
- 1月
- 2月
- 3月
- 4月
- 5月
- 6月
- 7月
- 8月
- 9月
- 10月
- 11月
- 12月
order:
- :year
- :month
- :day
datetime:
distance_in_words:
about_x_hours:
one: 約1時間
other: 約%{count}時間
about_x_months:
one: 約1ヶ月
other: 約%{count}ヶ月
about_x_years:
one: 約1年
other: 約%{count}年
almost_x_years:
one: 1年弱
other: ! '%{count}年弱'
half_a_minute: 30秒前後
less_than_x_minutes:
one: 1分以内
other: ! '%{count}分未満'
less_than_x_seconds:
one: 1秒以内
other: ! '%{count}秒未満'
over_x_years:
one: 1年以上
other: ! '%{count}年以上'
x_days:
one: 1日
other: ! '%{count}日'
x_minutes:
one: 1分
other: ! '%{count}分'
x_months:
one: 1ヶ月
other: ! '%{count}ヶ月'
x_seconds:
one: 1秒
other: ! '%{count}秒'
prompts:
day:
hour:
minute:
month:
second:
year:
errors: &errors
format: ! '%{attribute}%{message}'
messages:
accepted: を受諾してください。
blank: を入力してください。
present: は入力しないでください。
confirmation: と%{attribute}の入力が一致しません。
empty: を入力してください。
equal_to: は%{count}にしてください。
even: は偶数にしてください。
exclusion: は予約されています。
greater_than: は%{count}より大きい値にしてください。
greater_than_or_equal_to: は%{count}以上の値にしてください。
inclusion: は一覧にありません。
invalid: は不正な値です。
less_than: は%{count}より小さい値にしてください。
less_than_or_equal_to: は%{count}以下の値にしてください。
not_a_number: は数値で入力してください。
not_an_integer: は整数で入力してください。
odd: は奇数にしてください。
record_invalid: バリデーションに失敗しました。 %{errors}
restrict_dependent_destroy: ! '%{record}が存在しているので削除できません。'
taken: はすでに存在します。
too_long: は%{count}文字以内で入力してください。
too_short: は%{count}文字以上で入力してください。
wrong_length: は%{count}文字で入力してください。
other_than: "は%{count}以外の値にしてください。"
template:
body: 次の項目を確認してください。
header:
one: ! '%{model}にエラーが発生しました。'
other: ! '%{model}に%{count}個のエラーが発生しました。'
helpers:
select:
prompt: 選択してください。
submit:
create: 登録する
submit: 保存する
update: 更新する
number:
currency:
format:
delimiter: ! ','
format: ! '%n%u'
precision: 0
separator: .
significant: false
strip_insignificant_zeros: false
unit:
format:
delimiter: ! ','
precision: 3
separator: .
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: ! '%n %u'
units:
billion: 十億
million: 百万
quadrillion: 千兆
thousand:
trillion:
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: ! '%n%u'
units:
byte: バイト
gb: ギガバイト
kb: キロバイト
mb: メガバイト
tb: テラバイト
percentage:
format:
delimiter: ''
format: "%n%"
precision:
format:
delimiter: ''
support:
array:
last_word_connector:
two_words_connector:
words_connector:
time:
am: 午前
formats:
default: ! '%Y/%m/%d %H:%M:%S'
long: ! '%Y年%m月%d日(%a) %H時%M分%S秒 %z'
short: ! '%y/%m/%d %H:%M'
pm: 午後
# remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
activemodel:
errors:
<<: *errors
activerecord:
errors:
<<: *errors
devise:
confirmations:
confirmed: アカウントを登録しました。
send_instructions: 登録方法を数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。
failure:
already_authenticated: 既にログインしています。
inactive: アカウントが有効化されていません。
invalid: メールアドレスまたはパスワードが違います。
last_attempt: あと一回間違えるとアカウントが凍結されます。
locked: アカウントが凍結されています。
not_found_in_database: メールアドレスまたはパスワードが違います。
timeout: セッションがタイムアウトしました。もう一度ログインしてください。
unauthenticated: 続けるにはログインまたはアカウントを登録してください。
unconfirmed: 本登録を行ってください。
mailer:
confirmation_instructions:
subject: アカウントの登録方法
reset_password_instructions:
subject: パスワードの再設定
unlock_instructions:
subject: アカウントの凍結解除
omniauth_callbacks:
failure: 「%{reason}」のため、%{kind}による認証ができませんでした。
success: '%{kind}による認証に成功しました。'
passwords:
no_token: パスワード再設定のメール以外からこのページへアクセスする事はできません。もしパスワード再設定のメールに記載されたリンクをクリックしてこのページへ訪れた場合、不完全なURLのリンクをクリックしていないか確認してください。メーラーによっては、リンクのURLが途中で切れる可能性があります。
send_instructions: パスワードの再設定方法を数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にパスワード再設定のメールが届きます。
updated: パスワードを変更し、ログインしました。
updated_not_active: パスワードを変更しました。
registrations:
destroyed: アカウントを削除しました。またのご利用をお待ちしております。
signed_up: アカウント登録を受け付けました。
signed_up_but_inactive: 登録に成功しました。しかし、アカウントが有効になっていないためログインできません。
signed_up_but_locked: 登録に成功しました。しかし、アカウントがロックされているためログインできません。
signed_up_but_unconfirmed: アカウント確認のリンクが入っているメールを送りました。 メール内のリンクでアカウントを有効にしてください。
update_needs_confirmation: アカウント情報を変更しました。しかし、メールアドレスを確認する必要があります。メール内のリンクで新しいメールアドレスを確認してください。
updated: アカウント情報を更新しました。
sessions:
signed_in: ログインしました。
signed_out: ログアウトしました。
unlocks:
send_instructions: アカウントの凍結解除方法を数分以内にメールでご連絡します。
send_paranoid_instructions: アカウントが登録されていれば、数分以内にアカウントの凍結解除方法が登録しているアドレスに届きます。
unlocked: アカウントを凍結解除しました。続けるにはログインしてください。
errors:
messages:
already_confirmed: は既に登録済みです
confirmation_period_expired: は%{period}以内に確認が必要です。もう一度要求してください。
expired: は期限が切れたため、新しく取得する必要があります
not_found: は見つかりませんでした
not_locked: は凍結されていません
not_saved: '%{count}個のエラーにより%{resource}を保存することができませんでした。'
ja:
activerecord:
models:
post: post #g
post_tag: post_tag #g
tag: tag #g
user: user #g
attributes:
post:
author: :activerecord.models.author #g
body: body #g
post_tags: post_tags #g
tags: tags #g
title: title #g
post_tag:
post: :activerecord.models.post #g
tag: :activerecord.models.tag #g
tag:
ancestry: ancestry #g
name: name #g
post_tags: post_tags #g
posts: posts #g
user:
current_sign_in_at: current_sign_in_at #g
current_sign_in_ip: current_sign_in_ip #g
email: email #g
encrypted_password: encrypted_password #g
google_auth_token: google_auth_token #g
google_refresh_token: google_refresh_token #g
google_token_expires_at: google_token_expires_at #g
image_url: image_url #g
last_sign_in_at: last_sign_in_at #g
last_sign_in_ip: last_sign_in_ip #g
name: name #g
posts: posts #g
remember_created_at: remember_created_at #g
reset_password_sent_at: reset_password_sent_at #g
reset_password_token: reset_password_token #g
Rendezvous::Application.routes.draw do
root 'posts#index', as: 'root'
root 'home#top', as: 'root'
post 'posts/preview' => 'posts#preview'
get 'posts/show_fragment' => 'posts#show_fragment'
# get 'posts/show_fragment' => 'posts#show_fragment'
get 'posts/:id/fork' => 'posts#fork', as: 'fork_post'
get 'posts/:id/mail' => 'posts#mail', as: 'mail_post'
post 'posts/:id/mail' => 'posts#mail', as: 'mail_post'
resources :posts
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
......
......@@ -2,8 +2,8 @@ class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.string :email, null: false, default: ''
t.string :encrypted_password, null: false, default: ''
## Recoverable
t.string :reset_password_token
......@@ -13,7 +13,7 @@ class AddDeviseToUsers < ActiveRecord::Migration
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
......@@ -30,13 +30,12 @@ class AddDeviseToUsers < ActiveRecord::Migration
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
# Uncomment below if timestamps were not included in your original model.
# t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, :unique => true
# add_index :users, :unlock_token, :unique => true
end
......@@ -44,6 +43,6 @@ class AddDeviseToUsers < ActiveRecord::Migration
def self.down
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
raise ActiveRecord::IrreversibleMigration
fail ActiveRecord::IrreversibleMigration
end
end
class AddRefreshTokenToUser < ActiveRecord::Migration
def change
add_column :users, :google_refresh_token, :string
add_column :users, :google_token_expires_at, :datetime
end
end
......@@ -11,54 +11,56 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20131226161253) do
ActiveRecord::Schema.define(version: 20131228110818) do
create_table "post_tags", force: true do |t|
t.integer "post_id", null: false
t.integer "tag_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
create_table 'post_tags', force: true do |t|
t.integer 'post_id', null: false
t.integer 'tag_id', null: false
t.datetime 'created_at'
t.datetime 'updated_at'
end
add_index "post_tags", ["post_id"], name: "index_post_tags_on_post_id"
add_index "post_tags", ["tag_id"], name: "index_post_tags_on_tag_id"
add_index 'post_tags', ['post_id'], name: 'index_post_tags_on_post_id', using: :btree
add_index 'post_tags', ['tag_id'], name: 'index_post_tags_on_tag_id', using: :btree
create_table "posts", force: true do |t|
t.string "title"
t.text "body"
t.integer "author_id"
t.datetime "created_at"
t.datetime "updated_at"
create_table 'posts', force: true do |t|
t.string 'title'
t.text 'body'
t.integer 'author_id'
t.datetime 'created_at'
t.datetime 'updated_at'
end
create_table "tags", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "ancestry"
create_table 'tags', force: true do |t|
t.string 'name'
t.datetime 'created_at'
t.datetime 'updated_at'
t.string 'ancestry'
end
add_index "tags", ["ancestry"], name: "index_tags_on_ancestry"
add_index 'tags', ['ancestry'], name: 'index_tags_on_ancestry', using: :btree
create_table "users", force: true do |t|
t.string "name"
t.string "image_url"
t.datetime "created_at"
t.datetime "updated_at"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "google_auth_token"
create_table 'users', force: true do |t|
t.string 'name'
t.string 'image_url'
t.datetime 'created_at'
t.datetime 'updated_at'
t.string 'email', default: '', null: false
t.string 'encrypted_password', default: '', null: false
t.string 'reset_password_token'
t.datetime 'reset_password_sent_at'
t.datetime 'remember_created_at'
t.integer 'sign_in_count', default: 0, null: false
t.datetime 'current_sign_in_at'
t.datetime 'last_sign_in_at'
t.string 'current_sign_in_ip'
t.string 'last_sign_in_ip'
t.string 'google_auth_token'
t.string 'google_refresh_token'
t.datetime 'google_token_expires_at'
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index 'users', ['email'], name: 'index_users_on_email', unique: true, using: :btree
add_index 'users', ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true, using: :btree
end
......@@ -6,7 +6,6 @@
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
# Tag
_tag_tree = [
......@@ -31,7 +30,7 @@ _tag_tree = [
tags = []
_tag_tree.each do |_parent, _child|
puts "[Seed Tag] #{_parent} => #{_child}"
Rails.logger.debug "[Seed Tag] #{_parent} => #{_child}"
parent = Tag.find_or_create_by(name: _parent) if _parent
child = Tag.find_or_initialize_by(name: _child)
child.parent = parent if _parent
......@@ -39,28 +38,27 @@ _tag_tree.each do |_parent, _child|
tags << child
end
# User
User.find_or_create_by(name: '山田太郎') do |_u|
_u.email = "#{Devise.friendly_token[0,20]}@example.com"
_u.password = Devise.friendly_token[0,20]
_u.email = "#{Devise.friendly_token[0, 20]}@example.com"
_u.password = Devise.friendly_token[0, 20]
end
User.find_or_create_by(name: '鈴木二郎') do |_u|
_u.email = "#{Devise.friendly_token[0,20]}@example.com"
_u.password = Devise.friendly_token[0,20]
_u.email = "#{Devise.friendly_token[0, 20]}@example.com"
_u.password = Devise.friendly_token[0, 20]
end
User.find_or_create_by(name: '田中三郎') do |_u|
_u.email = "#{Devise.friendly_token[0,20]}@example.com"
_u.password = Devise.friendly_token[0,20]
_u.email = "#{Devise.friendly_token[0, 20]}@example.com"
_u.password = Devise.friendly_token[0, 20]
end
# Post
users = User.all
Dir.glob(Rails.root.join('db', 'seeds').to_s + '/*').each do |file_name|
puts "[Post Tag] #{file_name}"
Rails.logger.debug "[Post Tag] #{file_name}"
title = file_name.split('/').last
post = Post.find_or_initialize_by(title: title)
......@@ -69,4 +67,3 @@ Dir.glob(Rails.root.join('db', 'seeds').to_s + '/*').each do |file_name|
post.tags = [tags.sample, tags.sample]
post.save!
end
![Screen Shot 2013-11-20 at 12.23.19 AM.png](https://qiita-image-store.s3.amazonaws.com/0/10272/474c4435-35b5-60ee-18ef-dd11e2bbce3c.png "Screen Shot 2013-11-20 at 12.23.19 AM.png")
### 最終更新日
- 2013-12-10
......
require 'spec_helper'
class DummyClass; end
describe RV::Mailer do
let(:klass) { DummyClass.new.extend(RV::Mailer) }
let(:alice) { FactoryGirl.create(:alice) }
let(:post) { Post.create title: 'ruby rspec', body: 'This is first espec test: ruby' }
it 'valid' do
expect { klass.compose_mail(post, user: alice, to: 'dummy@example.com') }.not_to raise_error(ArgumentError)
end
it 'missing post' do
expect { klass.compose_mail(nil, user: alice, to: 'dummy@example.com') }.to raise_error(ArgumentError)
end
it 'missing user' do
expect { klass.compose_mail(post, user: nil, to: 'dummy@example.com') }.to raise_error(ArgumentError)
end
it 'missing to' do
expect { klass.compose_mail(post, user: alice, to: nil) }.to raise_error(ArgumentError)
end
it 'invalid to' do
expect { klass.compose_mail(post, user: alice, to: 'invalid.email') }.to raise_error(ArgumentError)
end
end
require 'spec_helper'
describe HomeController do
describe "GET 'top'" do
it 'should be successful' do
get :top
expect(response).to be_success
expect(response.code).to eq('200')
end
end
describe 'Login' do
before(:each) do
@user = FactoryGirl.create(:login_user_1)
sign_in @user
end
describe "GET 'top'" do
it 'should be successful' do
get :top
expect(subject).to redirect_to controller: 'posts',
action: 'index'
end
it 'should find the right user' do
get :top
expect(assigns(:current_user)).to eq(@user)
end
end
end
end
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :post do
title 'sample title'
body 'sample body'
after(:create) do |post|
create(:post_tag, post: post, tag: create(:tag_ruby))
end
end
factory :post_tag do
end
end
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :tag_ruby, class: Tag do
name 'ruby'
end
end
FactoryGirl.define do
factory :alice, class: User do
name 'Alice'
email 'alice@mail.com'
password Devise.friendly_token[0, 20]
google_token_expires_at Time.now + 30.minutes
end
factory :bob, class: User do
name 'Bob'
email 'bob@mail.com'
password Devise.friendly_token[0, 20]
google_token_expires_at Time.now - 1.hour
end
factory :login_user_1, class: User do
name 'Test User'
email 'example@example.com'
password 'changeme'
password_confirmation 'changeme'
# required if the Devise Confirmable module is used
# confirmed_at Time.now
end
end
require 'spec_helper'
include Warden::Test::Helpers
Warden.test_mode!
describe 'Request via js', js: true do
let(:user) { FactoryGirl.create(:login_user_1) }
before do
@post1 = Post.create title: 'ruby rspec', body: 'This is first espec test: ruby', author_id: user.id
@post2 = Post.create title: 'php test', body: 'PHP is very easy', author_id: user.id
@post3 = Post.create title: 'java java...', body: 'Java is not ruby...', author_id: user.id
end
before :each do
login_as user, scope: :user
visit '/posts'
end
it 'show first post' do
page.save_screenshot(Rails.root.join('tmp', 'screenshots', "a-#{Time.now.strftime('%Y-%m-%d %H%M%S')}.png"))
expect(page.find('#list_post div.title a').text).to include('ruby rspec')
end
it 'click post and show' do
find('.post-list:nth-child(3)').click
page.save_screenshot(Rails.root.join('tmp', 'screenshots', "b-#{Time.now.strftime('%Y-%m-%d %H%M%S')}.png"))
expect(page.find('#list_post div.title a').text).to include('java java...')
end
after :each do
page.driver.reset!
Warden.test_reset!
end
end
# Commonly used email steps
#
# To add your own steps make a custom_email_steps.rb
# The provided methods are:
#
# last_email_address
# reset_mailer
# open_last_email
# visit_in_email
# unread_emails_for
# mailbox_for
# current_email
# open_email
# read_emails_for
# find_email
#
# General form for email scenarios are:
# - clear the email queue (done automatically by email_spec)
# - execute steps that sends an email
# - check the user received an/no/[0-9] emails
# - open the email
# - inspect the email contents
# - interact with the email (e.g. click links)
#
# The Cucumber steps below are setup in this order.
# module EmailHelpers
# def current_email_address
# # Replace with your a way to find your current email. e.g @current_user.email
# # last_email_address will return the last email address used by email spec to find an email.
# # Note that last_email_address will be reset after each Scenario.
# last_email_address || "example@example.com"
# end
# end
# World(EmailHelpers)
# #
# # Reset the e-mail queue within a scenario.
# # This is done automatically before each scenario.
# #
# Given /^(?:a clear email queue|no emails have been sent)$/ do
# reset_mailer
# end
# #
# # Check how many emails have been sent/received
# #
# Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount|
# unread_emails_for(address).size.should == parse_email_count(amount)
# end
# Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount|
# mailbox_for(address).size.should == parse_email_count(amount)
# end
# Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject|
# unread_emails_for(address).select { |m| m.subject =~ Regexp.new(Regexp.escape(subject)) }.size.should == parse_email_count(amount)
# end
# Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject \/([^"]*?)\/$/ do |address, amount, subject|
# unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size.should == parse_email_count(amount)
# end
# Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body|
# open_email(address, :with_text => expected_body)
# end
# #
# # Accessing emails
# #
# # Opens the most recently received email
# When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address|
# open_email(address)
# end
# When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject|
# open_email(address, :with_subject => subject)
# end
# When /^(?:I|they|"([^"]*?)") opens? the email with subject \/([^"]*?)\/$/ do |address, subject|
# open_email(address, :with_subject => Regexp.new(subject))
# end
# When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text|
# open_email(address, :with_text => text)
# end
# When /^(?:I|they|"([^"]*?)") opens? the email with text \/([^"]*?)\/$/ do |address, text|
# open_email(address, :with_text => Regexp.new(text))
# end
# #
# # Inspect the Email Contents
# #
# Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text|
# current_email.should have_subject(text)
# end
# Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text|
# current_email.should have_subject(Regexp.new(text))
# end
# Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text|
# current_email.default_part_body.to_s.should include(text)
# end
# Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text|
# current_email.default_part_body.to_s.should =~ Regexp.new(text)
# end
# Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text|
# current_email.should be_delivered_from(text)
# end
# Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name|
# current_email.should have_header(name, text)
# end
# Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name|
# current_email.should have_header(name, Regexp.new(text))
# end
# Then /^I should see it is a multi\-part email$/ do
# current_email.should be_multipart
# end
# Then /^(?:I|they) should see "([^"]*?)" in the email html part body$/ do |text|
# current_email.html_part.body.to_s.should include(text)
# end
# Then /^(?:I|they) should see "([^"]*?)" in the email text part body$/ do |text|
# current_email.text_part.body.to_s.should include(text)
# end
# #
# # Inspect the Email Attachments
# #
# Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount|
# current_email_attachments.size.should == parse_email_count(amount)
# end
# Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename|
# current_email_attachments.select { |a| a.filename == filename }.size.should == parse_email_count(amount)
# end
# Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename|
# current_email_attachments[(index.to_i - 1)].filename.should == filename
# end
# Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type|
# current_email_attachments.select { |a| a.content_type.include?(content_type) }.size.should == parse_email_count(amount)
# end
# Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type|
# current_email_attachments[(index.to_i - 1)].content_type.should include(content_type)
# end
# Then /^all attachments should not be blank$/ do
# current_email_attachments.each do |attachment|
# attachment.read.size.should_not == 0
# end
# end
# Then /^show me a list of email attachments$/ do
# EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email)
# end
# #
# # Interact with Email Contents
# #
# When /^(?:I|they|"([^"]*?)") follows? "([^"]*?)" in the email$/ do |address, link|
# visit_in_email(link, address)
# end
# When /^(?:I|they) click the first link in the email$/ do
# click_first_link_in_email
# end
# #
# # Debugging
# # These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command.
# # Patches accepted. ;)
# #
# Then /^save and open current email$/ do
# EmailSpec::EmailViewer::save_and_open_email(current_email)
# end
# Then /^save and open all text emails$/ do
# EmailSpec::EmailViewer::save_and_open_all_text_emails
# end
# Then /^save and open all html emails$/ do
# EmailSpec::EmailViewer::save_and_open_all_html_emails
# end
# Then /^save and open all raw emails$/ do
# EmailSpec::EmailViewer::save_and_open_all_raw_emails
# end
require 'spec_helper'
describe Post do
describe 'Instance method' do
before :each do
@post = create(:post)
@alice = create(:alice)
end
describe 'Fork' do
subject { @post.generate_fork(@alice) }
it 'valid title' do
expect(subject.title).to eq('sample title')
end
it 'valid body' do
expect(subject.body).to eq('sample body')
end
it 'valid user' do
expect(subject.author).to eq(@alice)
end
it 'valid user' do
expect(subject.tags).to include(@post.tags.first)
end
end
end
describe 'scope :search' do
before :each do
@alice = create(:alice)
@post1 = Post.create id: 1001, title: 'ruby rspec', body: 'This is first espec test: ruby'
@post2 = Post.create id: 1002, title: 'php test', body: 'PHP is very easy', author_id: @alice.id
@post3 = Post.create id: 1003, title: 'java java...', body: 'Java is not ruby...', updated_at: Time.new(1989, 2, 25, 5, 30, 0)
@tag_java = Tag.create(name: 'java')
@post3.tags << @tag_java
end
it 'by id' do
expect(Post.search('id:1001')).to have(1).items
expect(Post.search('id:1001')).to include(@post1)
end
it 'by title' do
expect(Post.search('title:ruby')).to have(1).items
expect(Post.search('title:ruby')).to include(@post1)
end
it 'by body' do
expect(Post.search('body:ruby')).to have(2).items
expect(Post.search('body:ruby')).to include(@post3)
end
it 'by @<author_name>' do
expect(Post.search('@Alice')).to have(1).items
expect(Post.search('@Alice')).to include(@post2)
end
it 'by #<tag_name>' do
expect(Post.search('#java')).to have(1).items
expect(Post.search('#java')).to include(@post3)
end
it 'by date' do
expect(Post.search('date:1989-2-25')).to have(1).items
expect(Post.search('date:1989-2-25')).to include(@post3)
end
it 'by else' do
expect(Post.search('ruby')).to have(2).items
expect(Post.search('ruby')).to include(@post1)
expect(Post.search('ruby')).to include(@post3)
end
end
end
require 'spec_helper'
describe Tag do
pending "add some examples to (or delete) #{__FILE__}"
end
require 'spec_helper'
describe User do
describe 'Instance method' do
let(:alice) { create(:alice) }
let(:bob) { create(:bob) }
describe '#google_oauth_token_expired?' do
it 'not expired' do
expect(alice.google_oauth_token_expired?).to be_false
end
it 'expired' do
expect(bob.google_oauth_token_expired?).to be_true
end
end
end
describe 'validation' do
before(:each) do
@attr = {
name: 'Example User',
email: 'user@example.com',
password: 'changeme',
password_confirmation: 'changeme'
}
end
it 'should create a new instance given a valid attribute' do
User.create!(@attr)
end
it 'should require an email address' do
no_email_user = User.new(@attr.merge(email: ''))
no_email_user.should_not be_valid
end
it 'should accept valid email addresses' do
addresses = %w[user@foo.com THE_USER@foo.bar.org first.last@foo.jp]
addresses.each do |address|
valid_email_user = User.new(@attr.merge(email: address))
valid_email_user.should be_valid
end
end
it 'should reject invalid email addresses' do
addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
addresses.each do |address|
invalid_email_user = User.new(@attr.merge(email: address))
invalid_email_user.should_not be_valid
end
end
it 'should reject duplicate email addresses' do
User.create!(@attr)
user_with_duplicate_email = User.new(@attr)
user_with_duplicate_email.should_not be_valid
end
it 'should reject email addresses identical up to case' do
upcased_email = @attr[:email].upcase
User.create!(@attr.merge(email: upcased_email))
user_with_duplicate_email = User.new(@attr)
user_with_duplicate_email.should_not be_valid
end
describe 'passwords' do
before(:each) do
@user = User.new(@attr)
end
it 'should have a password attribute' do
@user.should respond_to(:password)
end
it 'should have a password confirmation attribute' do
@user.should respond_to(:password_confirmation)
end
end
describe 'password validations' do
it 'should require a password' do
User.new(@attr.merge(password: '', password_confirmation: '')).should_not be_valid
end
it 'should require a matching password confirmation' do
User.new(@attr.merge(password_confirmation: 'invalid')).should_not be_valid
end
it 'should reject short passwords' do
short = 'a' * 5
hash = @attr.merge(password: short, password_confirmation: short)
User.new(hash).should_not be_valid
end
end
describe 'password encryption' do
before(:each) do
@user = User.create!(@attr)
end
it 'should have an encrypted password attribute' do
@user.should respond_to(:encrypted_password)
end
it 'should set the encrypted password attribute' do
@user.encrypted_password.should_not be_blank
end
end
end
end
# coveralls
require 'coveralls'
Coveralls.wear!
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# require 'email_spec'
require 'factory_girl'
require 'capybara'
require 'capybara/rspec'
## Setting for polterguist.
require 'capybara/poltergeist'
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, timeout: 30)
end
Capybara.javascript_driver = :poltergeist
# Set capybara wait time (default: 2)
Capybara.default_wait_time = 10
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = 'random'
config.include FactoryGirl::Syntax::Methods
# config.include(EmailSpec::Helpers)
# config.include(EmailSpec::Matchers)
config.before(:all) do
FactoryGirl.reload
end
config.include Capybara::DSL
config.before :suite do
DatabaseRewinder.clean_all
end
# config.before :each do
# end
config.after :each do
DatabaseRewinder.clean
end
end
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
require 'test_helper'
class HomeControllerTest < ActionController::TestCase
test "should get show" do
get :show
assert_response :success
end
end
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
setup do
@post = posts(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:posts)
end
test "should get new" do
get :new
assert_response :success
end
test "should create post" do
assert_difference('Post.count') do
post :create, post: { body: @post.body, title: @post.title }
end
assert_redirected_to post_path(assigns(:post))
end
test "should show post" do
get :show, id: @post
assert_response :success
end
test "should get edit" do
get :edit, id: @post
assert_response :success
end
test "should update post" do
patch :update, id: @post, post: { body: @post.body, title: @post.title }
assert_redirected_to post_path(assigns(:post))
end
test "should destroy post" do
assert_difference('Post.count', -1) do
delete :destroy, id: @post
end
assert_redirected_to posts_path
end
end
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
title: MyString
body: MyText
two:
title: MyString
body: MyText
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
name: MyString
two:
name: MyString
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# This model initially had no columns defined. If you add columns to the
# model remove the '{}' from the fixture names and add the columns immediately
# below each fixture, per the syntax in the comments below
#
one: {}
# column: value
#
two: {}
# column: value
require 'test_helper'
class HomeHelperTest < ActionView::TestCase
end
require 'test_helper'
class PostsHelperTest < ActionView::TestCase
end
require 'test_helper'
class PostTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
require 'test_helper'
class TagTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
require 'test_helper'
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
ENV["RAILS_ENV"] ||= "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
ActiveRecord::Migration.check_pending!
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment