Ruby on Rails実践講座 - Twitterの簡易クローンを開発する
Twitterの簡易クローンを作りながら、Railsの基本を学習します。
開始する
$ cd ~/workspace
$ rails new tsubuyaki
$ cd tsubuyaki
26 | 26 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring |
27 | 27 | gem 'spring', group: :development |
28 | 28 | |
29 | gem 'sorcery' | |
30 | gem 'haml-rails' | |
31 | gem 'bootstrap-sass' | |
32 | ||
29 | 33 | # Use ActiveModel has_secure_password |
30 | 34 | # gem 'bcrypt', '~> 3.1.7' |
31 | 35 | |
@@ -26,6 +26,10 @@ gem 'sdoc', '~> 0.4.0', group: :doc |
$ bundle install
19 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. |
20 | 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] |
21 | 21 | # config.i18n.default_locale = :de |
22 | ||
23 | config.sass.preferred_syntax = :sass | |
22 | 24 | end |
23 | 25 | end |
@@ -19,5 +19,7 @@ class Application < Rails::Application |
$ rails g sorcery:install
$ rails g scaffold user -s --no-stylesheets --skip-migration
$ rails g migration add_name_and_screen_name_and_bio_to_users name:string screen_name:string bio:string
$ rake db:migrate
$ rails generate controller registrations new
13 | 13 | *= require_tree . |
14 | 14 | *= require_self |
15 | 15 | */ |
16 | ||
17 | @import bootstrap | |
@@ -13,3 +13,5 @@ |
6 | 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> |
7 | 7 | <%= csrf_meta_tags %> |
8 | 8 | </head> |
9 | <body> | |
9 | <body id="application"> | |
10 | 10 | |
11 | <%= yield %> | |
11 | <div> | |
12 | <%= yield %> | |
13 | </div> | |
12 | 14 | |
13 | 15 | </body> |
14 | 16 | </html> |
@@ -6,9 +6,11 @@ |
1 | 1 | Rails.application.routes.draw do |
2 | get 'registrations/new' | |
2 | resource :registrations, only: [:new, :create] | |
3 | 3 | |
4 | 4 | # The priority is based upon order of creation: first created -> highest priority. |
5 | 5 | # See how all your routes lay out with "rake routes". |
@@ -1,5 +1,5 @@ |
1 | 1 | class User < ActiveRecord::Base |
2 | 2 | authenticates_with_sorcery! |
3 | ||
4 | validates :name, presence: true, uniqueness: { case_sensitive: false }, format: { with: /\A[a-z][a-z0-9]+\z/ }, length: { in: 4..24 } | |
5 | validates :screen_name, length: { maximum: 140 } | |
6 | validates :bio, length: { maximum: 200 } | |
7 | validates :email, presence: true, uniqueness: { case_sensitive: false } | |
8 | validates :password, confirmation: true, length: { in: 6..24 }, if: :password | |
9 | validates :password_confirmation, presence: true, if: :password | |
3 | 10 | end |
@@ -1,3 +1,10 @@ |
1 | 1 | class RegistrationsController < ApplicationController |
2 | 2 | def new |
3 | @user = User.new | |
3 | 4 | end |
4 | 5 | end |
@@ -1,4 +1,5 @@ |
1 | 1 | %h1 Registrations#new |
2 | 2 | %p Find me in app/views/registrations/new.html.haml |
3 | ||
4 | = form_for @user, url: registrations_path, method: :post do |f| | |
5 | = f.label :name | |
6 | = f.text_field :name | |
7 | = f.label :email | |
8 | = f.text_field :email | |
9 | = f.label :password | |
10 | = f.password_field :password | |
11 | = f.label :password_confirmation | |
12 | = f.password_field :password_confirmation | |
13 | = f.submit | |
@@ -1,2 +1,13 @@ |
1 | 1 | Rails.application.routes.draw do |
2 | 2 | resource :registrations, only: [:new, :create] |
3 | 3 | |
4 | root to: 'registrations#new' | |
5 | ||
4 | 6 | # The priority is based upon order of creation: first created -> highest priority. |
5 | 7 | # See how all your routes lay out with "rake routes". |
6 | 8 | |
@@ -1,6 +1,8 @@ |
2 | 2 | def new |
3 | 3 | @user = User.new |
4 | 4 | end |
5 | ||
6 | def create | |
7 | @user = User.new(params_user) | |
8 | ||
9 | if @user.save | |
10 | redirect_to root_url | |
11 | else | |
12 | render :new | |
13 | end | |
14 | end | |
15 | ||
16 | private | |
17 | ||
18 | def params_user | |
19 | params.require(:user).permit(:name, :email, :password, :password_confirmation) | |
20 | end | |
5 | 21 | end |
@@ -2,4 +2,20 @@ class RegistrationsController < ApplicationController |
1 | 1 | %h1 Registrations#new |
2 | 2 | %p Find me in app/views/registrations/new.html.haml |
3 | 3 | |
4 | - @user.errors.each do |attr, message| | |
5 | .alert.alert-danger= message | |
6 | ||
4 | 7 | = form_for @user, url: registrations_path, method: :post do |f| |
5 | 8 | = f.label :name |
6 | 9 | = f.text_field :name |
@@ -1,6 +1,9 @@ |
18 | 18 | |
19 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. |
20 | 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] |
21 | # config.i18n.default_locale = :de | |
21 | config.i18n.default_locale = :ja | |
22 | 22 | |
23 | 23 | config.sass.preferred_syntax = :sass |
24 | 24 | end |
@@ -18,7 +18,7 @@ class Application < Rails::Application |
$ rails s
2 | 2 | activerecord: |
3 | 3 | errors: |
4 | 4 | models: |
5 | user: | |
6 | attributes: | |
7 | name: | |
8 | blank: ユーザー名は空ではいけません | |
9 | taken: ユーザー名は既に利用されています | |
10 | invalid: ユーザー名には半角英数字のみ利用できます | |
11 | too_long: ユーザー名は24文字まで利用できます | |
12 | too_short: ユーザー名は最短で4文字必要です | |
13 | email: | |
14 | blank: メールアドレスが空です | |
15 | taken: メールアドレスが既に使用済みです | |
16 | password: | |
17 | blank: パスワードが空です | |
18 | too_long: パスワードは24文字以内で利用できます | |
19 | too_short: パスワードは6文字以上で利用できます | |
20 | password_confirmation: | |
21 | blank: 確認用パスワードが空です | |
22 | confirmation: 確認用パスワードが一致しません | |
23 | bio: | |
24 | too_long: プロフィールは200文字以内でなければなりません | |
@@ -2,3 +2,23 @@ ja: |
1 | !!! | |
2 | %html | |
3 | %head | |
4 | %title Tsubuyaki22Nov | |
5 | = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true | |
6 | = javascript_include_tag 'application', 'data-turbolinks-track' => true | |
7 | = csrf_meta_tags | |
8 | %body#registrations | |
9 | = yield | |
@@ -0,0 +1,9 @@ |
15 | 15 | */ |
16 | 16 | |
17 | 17 | @import bootstrap |
18 | ||
19 | html, body | |
20 | width: 100% | |
21 | height: 100% | |
22 | ||
23 | .clear | |
24 | clear: both | |
@@ -15,3 +15,10 @@ |
1 | 1 | // Place all the styles related to the registrations controller here. |
2 | 2 | // They will automatically be included in application.css. |
3 | // You can use Sass here: http://sass-lang.com/ | |
3 | // You can use Sass (SCSS) here: http://sass-lang.com/ | |
4 | ||
5 | #registrations | |
6 | background-image: asset-url("back.jpg") | |
7 | background-position: center | |
8 | background-size: cover | |
9 | background-color: transparent | |
10 | background-repeat: no-repeat | |
11 | background-color: #050911 | |
12 | #registrations-new | |
13 | width: 100% | |
14 | height: 100% | |
15 | .left-content | |
16 | margin-top: 45px | |
17 | padding: 0px 45px | |
18 | color: #fff | |
19 | h1 | |
20 | font-size: 50px | |
21 | margin: 0px | |
22 | margin-top: 10px | |
23 | .ex | |
24 | font-size: 18px | |
25 | margin: 45px 0px | |
26 | .right-content | |
27 | padding: 0px 45px | |
28 | form | |
29 | margin: 45px 0px | |
30 | padding: 30px 35px | |
31 | border: 1px solid #fff | |
32 | border-radius: 6px | |
33 | background-color: rgba(0, 0, 0, 0.3) | |
34 | color: #fff | |
35 | h2 | |
36 | margin: 0px 0px 20px 0px | |
37 | border-bottom: 1px solid rgba(255, 255, 255, 0.5) | |
38 | padding-bottom: 10px | |
39 | font-size: 20px | |
40 | .control-label | |
41 | font-weight: 400 | |
42 | .btn | |
43 | width: 100% | |
44 | padding: 12px | |
45 | margin-top: 10px | |
46 | margin-bottom: 10px | |
47 | font-size: 16px | |
@@ -1,3 +1,47 @@ |
1 | %h1 Registrations#new | |
2 | %p Find me in app/views/registrations/new.html.haml | |
3 | ||
4 | - @user.errors.each do |attr, message| | |
5 | .alert.alert-danger= message | |
6 | ||
7 | = form_for @user, url: registrations_path, method: :post do |f| | |
8 | = f.label :name | |
9 | = f.text_field :name | |
10 | = f.label :email | |
11 | = f.text_field :email | |
12 | = f.label :password | |
13 | = f.password_field :password | |
14 | = f.label :password_confirmation | |
15 | = f.password_field :password_confirmation | |
16 | = f.submit | |
1 | #registrations-new | |
2 | .col-xs-6.left-content | |
3 | %h1 #Tsubuyaki | |
4 | %p.ex | |
5 | このサイトは、シラバスのRails学習コースの完成形サンプルアプリです。Microsoft Azure上で運用されています。 | |
6 | %p.by | |
7 | 開発者: @ohataken デザイン: @keito0904 企画: @saiwaki14 | |
8 | .col-xs-6.right-content | |
9 | = form_for @user, url: registrations_path, method: :post do |f| | |
10 | %h2 | |
11 | 会員登録する | |
12 | - @user.errors.each do |attr, message| | |
13 | .alert.alert-danger= message | |
14 | .form-group | |
15 | = f.label :name, "ユーザーID: @cyllabus_jp", class: "control-label" | |
16 | = f.text_field :name, class: "form-control" | |
17 | .form-group | |
18 | = f.label :email,"メールアドレス: hello@cyllabus.jp", class: "control-label" | |
19 | = f.text_field :email, class: "form-control" | |
20 | .form-group | |
21 | = f.label :password, "パスワード: 6文字以上", class: "control-label" | |
22 | = f.password_field :password, class: "form-control" | |
23 | .form-group | |
24 | = f.label :password_confirmation, "確認用パスワード: 6文字以上", class: "control-label" | |
25 | = f.password_field :password_confirmation, class: "form-control" | |
26 | = f.submit "登録する", class: "btn btn-primary" | |
27 | .clear | |
@@ -1,16 +1,27 @@ |
$ rails g controller sessions new
1 | 1 | Rails.application.routes.draw do |
2 | get 'sessions/new' | |
3 | ||
4 | 2 | resource :registrations, only: [:new, :create] |
3 | resource :sessions, only: [:new, :create, :destroy] | |
5 | 4 | |
6 | 5 | root to: 'registrations#new' |
7 | 6 | |
@@ -1,7 +1,6 @@ |
45 | 45 | margin-top: 10px |
46 | 46 | margin-bottom: 10px |
47 | 47 | font-size: 16px |
48 | .login | |
49 | color: #fff | |
50 | text-decoration: underline | |
@@ -45,3 +45,6 @@ |
24 | 24 | = f.label :password_confirmation, "確認用パスワード: 6文字以上", class: "control-label" |
25 | 25 | = f.password_field :password_confirmation, class: "form-control" |
26 | 26 | = f.submit "登録する", class: "btn btn-primary" |
27 | = link_to "ログインする", new_sessions_path, class: "login pull-right" | |
27 | 28 | .clear |
@@ -24,4 +24,5 @@ |
1 | 1 | class SessionsController < ApplicationController |
2 | 2 | def new |
3 | @user = User.new | |
3 | 4 | end |
4 | 5 | end |
@@ -1,4 +1,5 @@ |
1 | 1 | %h1 Sessions#new |
2 | 2 | %p Find me in app/views/sessions/new.html.haml |
3 | ||
4 | = form_for @user, url: sessions_path, method: :post do |f| | |
5 | = f.label :email | |
6 | = f.text_field :email | |
7 | = f.label :password | |
8 | = f.password_field :password | |
9 | = f.submit | |
@@ -1,2 +1,9 @@ |
2 | 2 | def new |
3 | 3 | @user = User.new |
4 | 4 | end |
5 | ||
6 | def create | |
7 | email = params_user[:email] | |
8 | password = params_user[:password] | |
9 | ||
10 | if login(email, password) | |
11 | redirect_to root_url, notice: "successfully logged in." | |
12 | else | |
13 | @user = User.new(email: email) | |
14 | render :new | |
15 | end | |
16 | end | |
17 | ||
18 | private | |
19 | ||
20 | def params_user | |
21 | params.require(:user).permit(:email, :password) | |
22 | end | |
5 | 23 | end |
@@ -2,4 +2,22 @@ class SessionsController < ApplicationController |
1 | 1 | %h1 Sessions#new |
2 | 2 | %p Find me in app/views/sessions/new.html.haml |
3 | 3 | |
4 | - if action_name == "create" | |
5 | .alert.alert-danger | |
6 | メールアドレスまたはパスワードが正しくありません。 | |
7 | ||
4 | 8 | = form_for @user, url: sessions_path, method: :post do |f| |
5 | 9 | = f.label :email |
6 | 10 | = f.text_field :email |
@@ -1,6 +1,10 @@ |
1 | !!! | |
2 | %html | |
3 | %head | |
4 | %title Tsubuyaki18Oct | |
5 | = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true | |
6 | = javascript_include_tag 'application', 'data-turbolinks-track' => true | |
7 | = csrf_meta_tags | |
8 | %body#sessions | |
9 | = yield | |
@@ -0,0 +1,9 @@ |
1 | 1 | // Place all the styles related to the sessions controller here. |
2 | 2 | // They will automatically be included in application.css. |
3 | // You can use Sass here: http://sass-lang.com/ | |
3 | // You can use Sass (SCSS) here: http://sass-lang.com/ | |
4 | ||
5 | #sessions | |
6 | display: table | |
7 | widows: 100% | |
8 | height: 100% | |
9 | background-color: #f5f5f5 | |
10 | #sessions-new | |
11 | display: table-cell | |
12 | vertical-align: middle | |
13 | .login-content | |
14 | margin: 0 auto | |
15 | float: none | |
16 | form | |
17 | border: 1px solid #ddd | |
18 | border-bottom-width: 3px | |
19 | border-radius: 6px | |
20 | background-color: #fff | |
21 | h2 | |
22 | margin: 0px | |
23 | padding: 12px | |
24 | text-align: center | |
25 | border-bottom: 2px solid #ddd | |
26 | font-size: 18px | |
27 | font-weight: 600 | |
28 | .form-body | |
29 | padding: 25px 30px | |
30 | .control-label | |
31 | font-weight: 400 | |
32 | .btn | |
33 | width: 100% | |
34 | margin: 10px 0px | |
35 | .signup | |
36 | text-decoration: underline | |
@@ -1,3 +1,36 @@ |
1 | %h1 Sessions#new | |
2 | %p Find me in app/views/sessions/new.html.haml | |
3 | ||
4 | - if action_name == "create" | |
5 | .alert.alert-danger | |
6 | メールアドレスまたはパスワードが正しくありません。 | |
7 | ||
8 | = form_for @user, url: sessions_path, method: :post do |f| | |
9 | = f.label :email | |
10 | = f.text_field :email | |
11 | = f.label :password | |
12 | = f.password_field :password | |
13 | = f.submit | |
1 | #sessions-new | |
2 | .col-xs-5.login-content | |
3 | - if action_name == "create" | |
4 | .alert.alert-danger | |
5 | メールアドレスまたはパスワードが正しくありません。 | |
6 | = form_for @user, url: sessions_path, method: :post do |f| | |
7 | %h2 | |
8 | ログイン | |
9 | .form-body | |
10 | .form-group | |
11 | = f.label :email,"メールアドレス:hello@cyllabus.jp", class: "control-label" | |
12 | = f.text_field :email, class: "form-control" | |
13 | .form-group | |
14 | = f.label :password, "パスワード:6文字以上", class: "control-label" | |
15 | = f.password_field :password, class: "form-control" | |
16 | = f.submit "ログイン", class: "btn btn-success" | |
17 | = link_to root_path, class: "pull-right signup" do | |
18 | 会員登録する | |
19 | .clear | |
@@ -1,13 +1,19 @@ |
$ rails g scaffold user -s --no-stylesheets --skip-migration
resource :registrations, only: [:new, :create]
resource :sessions, only: [:new, :create, :destroy]
resources :users, only: [:index, :show]
1 | 1 | class UsersController < ApplicationController |
2 | before_action :set_user, only: [:show, :edit, :update, :destroy] | |
3 | ||
4 | 2 | # GET /users |
5 | 3 | # GET /users.json |
6 | 4 | def index |
@@ -1,6 +1,4 @@ | ||
10 | 8 | # GET /users/1 |
11 | 9 | # GET /users/1.json |
12 | 10 | def show |
11 | @user = User.find(params[:id]) | |
13 | 12 | end |
14 | 13 | end |
@@ -10,5 +8,6 @@ def index |
%h1 Listing users
%table
%tr
%th
- @users.each do |user|
%tr
%td= link_to user.name, user
1 | 1 | %p#notice= notice |
2 | 2 | |
3 | ||
4 | = link_to 'Edit', edit_user_path(@user) | |
5 | \| | |
6 | 3 | = link_to 'Back', users_path |
@@ -1,6 +1,3 @@ |
22 | 22 | |
23 | 23 | .clear |
24 | 24 | clear: both |
25 | ||
26 | #users-content | |
27 | float: none | |
28 | margin: 0 auto 35px | |
29 | padding: 0px | |
30 | background-color: #fff | |
31 | border: 1px solid #ddd | |
32 | border-radius: 6px | |
33 | border-bottom-width: 3px | |
34 | .list-group | |
35 | margin-bottom: -1px | |
36 | .list-group-item | |
37 | border: none | |
38 | border-bottom: 1px solid #ddd | |
39 | margin-bottom: 0px | |
40 | &:last-child | |
41 | .user | |
42 | .user-name | |
43 | a | |
44 | color: #555 | |
45 | .user-id | |
46 | font-size: 14px | |
47 | color: #aaa | |
48 | font-weight: 400 | |
49 | .time | |
50 | font-size: 12px | |
51 | color: #aaa | |
52 | font-weight: 400 | |
53 | .user-list | |
54 | border-bottom-width: 2px | |
55 | h2 | |
56 | font-size: 20px | |
57 | margin: 0px | |
@@ -22,3 +22,36 @@ html, body |
1 | %h1 Listing users | |
2 | ||
3 | %table | |
4 | %tr | |
5 | %th | |
6 | ||
7 | - @users.each do |user| | |
8 | %tr | |
9 | %td= link_to 'Show', user | |
1 | .col-xs-8#users-content | |
2 | .list-group | |
3 | .list-group-item.user-list | |
4 | %h2 ユーザー一覧 | |
5 | = div_for @users, class: "list-group-item" do |u| | |
6 | %h4.user | |
7 | %span.user-name | |
8 | = link_to u.name, user_path(u) | |
9 | %span.user-id | |
10 | @#{u.name} | |
11 | .bio | |
12 | = u.bio | |
@@ -1,9 +1,12 @@ |
1 | %p#notice= notice | |
2 | ||
3 | = link_to 'Back', users_path | |
1 | .col-xs-8#users-content | |
2 | .user-info | |
3 | %span.user-name | |
4 | = @user.name | |
5 | %span.user-id | |
6 | @#{@user.name} | |
7 | .bio | |
8 | = @user.bio | |
@@ -1,3 +1,8 @@ |
55 | 55 | h2 |
56 | 56 | font-size: 20px |
57 | 57 | margin: 0px |
58 | .user-info | |
59 | padding: 20px 35px | |
60 | .user-name | |
61 | font-size: 28px | |
62 | font-weight: 600 | |
63 | .user-id | |
64 | font-size: 18px | |
65 | color: #aaa | |
66 | .bio | |
67 | margin-top: 5px | |
68 | .nav.nav-tabs | |
69 | border-top: 1px solid #ddd | |
70 | border-bottom: 2px solid #ddd | |
71 | li | |
72 | a | |
73 | border: none | |
74 | &:hover | |
75 | background-color: #fff | |
76 | .text | |
77 | .num | |
78 | font-size: 28px | |
@@ -55,3 +55,24 @@ html, body |
1 | .navbar.navbar-default | |
2 | .container | |
3 | .navbar-header | |
4 | = link_to '#Tsubuyaki', root_url, class: "navbar-brand" | |
5 | - if logged_in? | |
6 | %ul.nav.navbar-nav | |
7 | %li= link_to "ユーザー一覧", users_path | |
8 | %ul.nav.navbar-nav.navbar-right | |
9 | %li= link_to current_user.name, current_user | |
10 | %li= link_to "ログアウト", sessions_path, method: :delete | |
11 | - else | |
12 | %ul.nav.navbar-nav.navbar-right | |
13 | %li= link_to "会員登録", new_registrations_path | |
14 | %li= link_to "ログイン", new_sessions_path | |
@@ -0,0 +1,14 @@ |
9 | 9 | <body id="application"> |
10 | 10 | |
11 | 11 | <div> |
12 | <%= render partial: "layouts/header" %> | |
12 | 13 | <%= yield %> |
13 | 14 | </div> |
14 | 15 | |
@@ -9,6 +9,7 @@ |
$ rails g controller settings edit
1 | 1 | Rails.application.routes.draw do |
2 | 2 | |
3 | get 'settings/edit' | |
4 | ||
5 | 3 | resource :registrations, only: [:new, :create] |
6 | 4 | resource :sessions, only: [:new, :create, :destroy] |
5 | resource :settings, only: [:edit, :update] | |
7 | 6 | resources :users, only: [:index, :show] |
8 | 7 | |
9 | 8 | root to: 'registrations#new' |
@@ -1,9 +1,8 @@ |
1 | 1 | class SettingsController < ApplicationController |
2 | 2 | def edit |
3 | @user = current_user | |
3 | 4 | end |
4 | 5 | end |
@@ -1,4 +1,5 @@ |
2 | 2 | def edit |
3 | 3 | @user = current_user |
4 | 4 | end |
5 | ||
6 | def update | |
7 | @user = current_user | |
8 | @user.update_attributes(params_user) | |
9 | redirect_to user_url(@user) | |
10 | end | |
11 | ||
12 | private | |
13 | ||
14 | def params_user | |
15 | params.require(:user).permit(:name, :screen_name, :bio) | |
16 | end | |
5 | 17 | end |
@@ -2,4 +2,16 @@ class SettingsController < ApplicationController |
1 | 1 | %h1 Settings#edit |
2 | 2 | %p Find me in app/views/settings/edit.html.haml |
3 | ||
4 | = form_for @user, url: settings_path, method: :put do |f| | |
5 | = f.label :name | |
6 | = f.text_field :name | |
7 | = f.label :screen_name | |
8 | = f.text_field :screen_name | |
9 | = f.label :bio | |
10 | = f.text_area :bio | |
11 | = f.submit | |
@@ -1,2 +1,11 @@ |
7 | 7 | %li= link_to "ユーザー一覧", users_path |
8 | 8 | %ul.nav.navbar-nav.navbar-right |
9 | 9 | %li= link_to current_user.name, current_user |
10 | %li= link_to "設定", edit_settings_path | |
10 | 11 | %li= link_to "ログアウト", sessions_path, method: :delete |
11 | 12 | - else |
12 | 13 | %ul.nav.navbar-nav.navbar-right |
@@ -7,6 +7,7 @@ |
1 | 1 | module UsersHelper |
2 | def render_user_screen_name user | |
3 | if user.screen_name.blank? | |
4 | user.name | |
5 | else | |
6 | user.screen_name | |
7 | end | |
8 | end | |
2 | 9 | end |
@@ -1,2 +1,9 @@ |
5 | 5 | = div_for @users, class: "list-group-item" do |u| |
6 | 6 | %h4.user |
7 | 7 | %span.user-name |
8 | = link_to u.name, user_path(u) | |
8 | = link_to render_user_screen_name(u), user_path(u) | |
9 | 9 | %span.user-id |
10 | 10 | @#{u.name} |
11 | 11 | .bio |
@@ -5,7 +5,7 @@ |
1 | 1 | .col-xs-8#users-content |
2 | 2 | .user-info |
3 | 3 | %span.user-name |
4 | = @user.name | |
4 | = render_user_screen_name(@user) | |
5 | 5 | %span.user-id |
6 | 6 | @#{@user.name} |
7 | 7 | .bio |
@@ -1,7 +1,7 @@ |
1 | %h1 Settings#edit | |
2 | %p Find me in app/views/settings/edit.html.haml | |
3 | ||
4 | = form_for @user, url: settings_path, method: :put do |f| | |
5 | = f.label :name | |
6 | = f.text_field :name | |
7 | = f.label :screen_name | |
8 | = f.text_field :screen_name | |
9 | = f.label :bio | |
10 | = f.text_area :bio | |
11 | = f.submit | |
1 | #settings-edit | |
2 | .col-xs-6.settings-content | |
3 | = form_for @user, url: settings_path, method: :put do |f| | |
4 | %h2 | |
5 | 設定 | |
6 | .form-body | |
7 | .form-group | |
8 | = f.label :name, "ユーザーID: @cyllabus_jp", class: "control-label" | |
9 | = f.text_field :name, class: "form-control" | |
10 | .form-group | |
11 | = f.label :screen_name, "表示名: シラバス", class: "control-label" | |
12 | = f.text_field :screen_name, class: "form-control" | |
13 | .form-group | |
14 | = f.label :bio, "プロフィール(200文字)", class: "control-label" | |
15 | = f.text_area :bio, class: "form-control" | |
16 | = f.submit "送信する", class: "btn btn-success" | |
@@ -1,11 +1,16 @@ |
1 | 1 | // Place all the styles related to the settings controller here. |
2 | 2 | // They will automatically be included in application.css. |
3 | 3 | // You can use Sass here: http://sass-lang.com/ |
4 | ||
5 | #settings-edit | |
6 | .settings-content | |
7 | float: none | |
8 | margin: 0 auto 35px | |
9 | form | |
10 | border: 1px solid #ddd | |
11 | border-bottom-width: 3px | |
12 | border-radius: 6px | |
13 | background-color: #fff | |
14 | h2 | |
15 | margin: 0px | |
16 | padding: 12px | |
17 | text-align: center | |
18 | border-bottom: 2px solid #ddd | |
19 | font-size: 18px | |
20 | font-weight: 600 | |
21 | .form-body | |
22 | padding: 25px 30px | |
23 | .control-label | |
24 | font-weight: 400 | |
25 | textarea | |
26 | height: 100px | |
27 | .btn | |
28 | width: 100% | |
29 | margin: 10px 0px | |
@@ -1,3 +1,29 @@ |
5 | 5 | |
6 | 6 | def update |
7 | 7 | @user = current_user |
8 | @user.update_attributes(params_user) | |
9 | redirect_to user_url(@user) | |
8 | if @user.update_attributes(params_user) | |
9 | redirect_to user_url(@user) | |
10 | else | |
11 | render :edit | |
12 | end | |
10 | 13 | end |
11 | 14 | |
12 | 15 | private |
@@ -5,8 +5,11 @@ def edit |
1 | 1 | #settings-edit |
2 | 2 | .col-xs-6.settings-content |
3 | - @user.errors.each do |attr, message| | |
4 | .alert.alert-danger= message | |
3 | 5 | = form_for @user, url: settings_path, method: :put do |f| |
4 | 6 | %h2 |
5 | 7 | 設定 |
@@ -1,5 +1,7 @@ |
20 | 20 | width: 100% |
21 | 21 | height: 100% |
22 | 22 | |
23 | #application | |
24 | background-color: #f5f5f5 | |
25 | ||
23 | 26 | .clear |
24 | 27 | clear: both |
25 | 28 | |
@@ -20,6 +20,9 @@ html, body |
15 | 15 | end |
16 | 16 | end |
17 | 17 | |
18 | def destroy | |
19 | logout | |
20 | redirect_to root_url | |
21 | end | |
22 | ||
18 | 23 | private |
19 | 24 | |
20 | 25 | def params_user |
@@ -15,6 +15,11 @@ def create |
1 | 1 | class UsersController < ApplicationController |
2 | before_filter :require_login | |
3 | ||
2 | 4 | # GET /users |
3 | 5 | # GET /users.json |
4 | 6 | def index |
@@ -1,4 +1,6 @@ |
6 | 6 | def update |
7 | 7 | @user = current_user |
8 | 8 | if @user.update_attributes(params_user) |
9 | redirect_to user_url(@user) | |
9 | redirect_to user_url(@user), notice: "プロフィールを更新しました" | |
10 | 10 | else |
11 | 11 | render :edit |
12 | 12 | end |
@@ -6,7 +6,7 @@ def edit |
1 | 1 | .col-xs-8#users-content |
2 | 2 | .user-info |
3 | - if notice | |
4 | .alert.alert-info= notice | |
3 | 5 | %span.user-name |
4 | 6 | = render_user_screen_name(@user) |
5 | 7 | %span.user-id |
@@ -1,5 +1,7 @@ |
8 | 8 | password = params_user[:password] |
9 | 9 | |
10 | 10 | if login(email, password) |
11 | redirect_to root_url, notice: "successfully logged in." | |
11 | redirect_to root_url, notice: "サインインしました" | |
12 | 12 | else |
13 | 13 | @user = User.new(email: email) |
14 | 14 | render :new |
@@ -8,7 +8,7 @@ def create |
17 | 17 | |
18 | 18 | def destroy |
19 | 19 | logout |
20 | redirect_to root_url | |
20 | redirect_to root_url, notice: "サインアウトしました" | |
21 | 21 | end |
22 | 22 | |
23 | 23 | private |
@@ -17,7 +17,7 @@ def create |
5 | 5 | このサイトは、シラバスのRails学習コースの完成形サンプルアプリです。Microsoft Azure上で運用されています。 |
6 | 6 | %p.by |
7 | 7 | 開発者: @ohataken デザイン: @keito0904 企画: @saiwaki14 |
8 | - if notice | |
9 | %p | |
10 | .alert.alert-info= notice | |
8 | 11 | .col-xs-6.right-content |
9 | 12 | = form_for @user, url: registrations_path, method: :post do |f| |
10 | 13 | %h2 |
@@ -5,6 +5,9 @@ |
$ rails g scaffold tweet user_id:integer content:string --no-stylesheets
5 | 5 | t.string :content |
6 | 6 | |
7 | 7 | t.timestamps |
8 | ||
9 | t.index :user_id | |
10 | t.index :created_at | |
8 | 11 | end |
9 | 12 | end |
10 | 13 | end |
@@ -5,6 +5,9 @@ def change |
$ rake db:migrate
4 | 4 | = link_to '#Tsubuyaki', root_url, class: "navbar-brand" |
5 | 5 | - if logged_in? |
6 | 6 | %ul.nav.navbar-nav |
7 | %li= link_to "全ツイート一覧", tweets_path | |
7 | 8 | %li= link_to "ユーザー一覧", users_path |
8 | 9 | %ul.nav.navbar-nav.navbar-right |
9 | 10 | %li= link_to current_user.name, current_user |
@@ -4,6 +4,7 @@ |
7 | 7 | @user = User.new(params_user) |
8 | 8 | |
9 | 9 | if @user.save |
10 | login(@user.email, @user.password) | |
10 | 11 | redirect_to root_url |
11 | 12 | else |
12 | 13 | render :new |
@@ -7,6 +7,7 @@ def create |
1 | 1 | Rails.application.routes.draw do |
2 | 2 | |
3 | resources :tweets | |
4 | ||
5 | 3 | resource :registrations, only: [:new, :create] |
6 | 4 | resource :sessions, only: [:new, :create, :destroy] |
7 | 5 | resource :settings, only: [:edit, :update] |
8 | 6 | resources :users, only: [:index, :show] |
7 | resources :tweets | |
9 | 8 | |
10 | 9 | root to: 'registrations#new' |
11 | 10 | |
@@ -1,11 +1,10 @@ |
25 | 25 | # POST /tweets.json |
26 | 26 | def create |
27 | 27 | @tweet = Tweet.new(tweet_params) |
28 | @tweet.user = current_user | |
28 | 29 | |
29 | 30 | respond_to do |format| |
30 | 31 | if @tweet.save |
@@ -25,6 +25,7 @@ def edit | ||
69 | 70 | |
70 | 71 | # Never trust parameters from the scary internet, only allow the white list through. |
71 | 72 | def tweet_params |
72 | params.require(:tweet).permit(:user_id, :content) | |
73 | params.require(:tweet).permit(:content) | |
73 | 74 | end |
74 | 75 | end |
@@ -69,6 +70,6 @@ def set_tweet |
1 | 1 | class TweetsController < ApplicationController |
2 | before_filter :require_login, except: [:index] | |
2 | 3 | before_action :set_tweet, only: [:show, :edit, :update, :destroy] |
3 | 4 | |
4 | 5 | # GET /tweets |
@@ -1,4 +1,5 @@ |
1 | 1 | class Tweet < ActiveRecord::Base |
2 | belongs_to :user | |
2 | 3 | end |
@@ -1,2 +1,3 @@ |
1 | 1 | class User < ActiveRecord::Base |
2 | 2 | authenticates_with_sorcery! |
3 | 3 | |
4 | has_many :tweets, dependent: :destroy | |
5 | ||
4 | 6 | validates :name, presence: true, uniqueness: { case_sensitive: false }, format: { with: /\A[a-z][a-z0-9]+\z/ }, length: { in: 4..24 } |
5 | 7 | validates :screen_name, length: { maximum: 140 } |
6 | 8 | validates :bio, length: { maximum: 200 } |
@@ -1,6 +1,8 @@ |
class Tweet < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
validates :content, presence: true, length: { in: 1..140}
end
1 | %h1 Listing tweets | |
2 | ||
3 | %table | |
4 | %tr | |
5 | %th User | |
6 | %th Content | |
7 | %th | |
8 | %th | |
9 | %th | |
10 | ||
11 | - @tweets.each do |tweet| | |
12 | %tr | |
13 | %td= tweet.user_id | |
14 | %td= tweet.content | |
15 | %td= link_to 'Show', tweet | |
16 | %td= link_to 'Edit', edit_tweet_path(tweet) | |
17 | %td= link_to 'Destroy', tweet, :method => :delete, :data => { :confirm => 'Are you sure?' } | |
18 | ||
19 | %br | |
20 | ||
21 | = link_to 'New Tweet', new_tweet_path | |
@@ -1,21 +0,0 @@ |
1 | #tweets-content | |
2 | .container | |
3 | .row | |
4 | .col-xs-4.left-content | |
5 | - if logged_in? | |
6 | .panel.panel-default | |
7 | .panel-body | |
8 | = link_to user_path(current_user), class: "user" do | |
9 | %span.user-name | |
10 | = render_user_screen_name current_user | |
11 | %span.user-id | |
12 | @#{current_user.name} | |
13 | .user-activity | |
14 | .row | |
15 | .col-xs-4.tweets-num | |
16 | .text | |
17 | つぶやき | |
18 | .num | |
19 | = link_to current_user.tweets.count, user_path(current_user) | |
20 | .col-xs-4.follow-num | |
21 | .text | |
22 | フォロー | |
23 | .num | |
24 | 0 | |
25 | .col-xs-4.follower-num | |
26 | .text | |
27 | フォロワー | |
28 | .num | |
29 | 0 | |
30 | .col-xs-8.right-content | |
31 | .list-group | |
32 | = div_for @tweets, class: "list-group-item" do |t| | |
33 | %h4.user | |
34 | %span.user-name | |
35 | = link_to render_user_screen_name(t.user), user_path(t.user) | |
36 | %span.user-id | |
37 | @#{t.user.name} | |
38 | %span.time.pull-right | |
39 | = distance_of_time_in_words_to_now(t.created_at) | |
40 | .clear | |
41 | .tweet-content | |
42 | %p | |
43 | = t.content | |
@@ -0,0 +1,43 @@ |
79 | 79 | .text |
80 | 80 | .num |
81 | 81 | font-size: 28px |
82 | ||
83 | #tweets-content | |
84 | .left-content | |
85 | .panel | |
86 | box-shadow: none | |
87 | border-bottom-width: 3px | |
88 | .user | |
89 | .user-name | |
90 | font-size: 20px | |
91 | font-weight: 600 | |
92 | color: #555 | |
93 | .user-id | |
94 | color: #aaa | |
95 | &:hover | |
96 | text-decoration: none | |
97 | border-bottom: 1px solid #555 | |
98 | .user-activity | |
99 | text-align: center | |
100 | .row | |
101 | border-bottom: 1px solid #ddd | |
102 | padding: 10px 0px | |
103 | .text | |
104 | font-size: 12px | |
105 | color: #777 | |
106 | .num | |
107 | font-size: 18px | |
108 | .right-content | |
109 | .list-group-item:last-child | |
110 | border-bottom-width: 3px | |
111 | .list-group-item | |
112 | .user | |
113 | .user-name | |
114 | a | |
115 | color: #555 | |
116 | .user-id | |
117 | font-size: 14px | |
118 | color: #aaa | |
119 | font-weight: 400 | |
120 | .time | |
121 | font-size: 12px | |
122 | color: #aaa | |
123 | font-weight: 400 | |
124 | .tweet-content | |
125 | font-size: 16px | |
126 | .content-footer | |
127 | a | |
128 | font-size: 12px | |
129 | margin-right: 10px | |
@@ -79,3 +79,51 @@ html, body |
22 | 22 | confirmation: 確認用パスワードが一致しません |
23 | 23 | bio: |
24 | 24 | too_long: プロフィールは200文字以内でなければなりません |
25 | date: | |
26 | abbr_day_names: | |
27 | - 日 | |
28 | - 月 | |
29 | - 火 | |
30 | - 水 | |
31 | - 木 | |
32 | - 金 | |
33 | - 土 | |
34 | abbr_month_names: | |
35 | - | |
36 | - 1月 | |
37 | - 2月 | |
38 | - 3月 | |
39 | - 4月 | |
40 | - 5月 | |
41 | - 6月 | |
42 | - 7月 | |
43 | - 8月 | |
44 | - 9月 | |
45 | - 10月 | |
46 | - 11月 | |
47 | - 12月 | |
48 | day_names: | |
49 | - 日曜日 | |
50 | - 月曜日 | |
51 | - 火曜日 | |
52 | - 水曜日 | |
53 | - 木曜日 | |
54 | - 金曜日 | |
55 | - 土曜日 | |
56 | formats: | |
57 | default: ! '%Y/%m/%d' | |
58 | long: ! '%Y年%m月%d日(%a)' | |
59 | short: ! '%m/%d' | |
60 | month_names: | |
61 | - | |
62 | - 1月 | |
63 | - 2月 | |
64 | - 3月 | |
65 | - 4月 | |
66 | - 5月 | |
67 | - 6月 | |
68 | - 7月 | |
69 | - 8月 | |
70 | - 9月 | |
71 | - 10月 | |
72 | - 11月 | |
73 | - 12月 | |
74 | order: | |
75 | - :year | |
76 | - :month | |
77 | - :day | |
78 | datetime: | |
79 | distance_in_words: | |
80 | about_x_hours: | |
81 | one: 約1時間 | |
82 | other: 約%{count}時間 | |
83 | about_x_months: | |
84 | one: 約1ヶ月 | |
85 | other: 約%{count}ヶ月 | |
86 | about_x_years: | |
87 | one: 約1年 | |
88 | other: 約%{count}年 | |
89 | almost_x_years: | |
90 | one: 1年弱 | |
91 | other: ! '%{count}年弱' | |
92 | half_a_minute: 30秒前後 | |
93 | less_than_x_minutes: | |
94 | one: 1分以内 | |
95 | other: ! '%{count}分未満' | |
96 | less_than_x_seconds: | |
97 | one: 1秒以内 | |
98 | other: ! '%{count}秒未満' | |
99 | over_x_years: | |
100 | one: 1年以上 | |
101 | other: ! '%{count}年以上' | |
102 | x_days: | |
103 | one: 1日 | |
104 | other: ! '%{count}日' | |
105 | x_minutes: | |
106 | one: 1分 | |
107 | other: ! '%{count}分' | |
108 | x_months: | |
109 | one: 1ヶ月 | |
110 | other: ! '%{count}ヶ月' | |
111 | x_seconds: | |
112 | one: 1秒 | |
113 | other: ! '%{count}秒' | |
114 | prompts: | |
115 | day: 日 | |
116 | hour: 時 | |
117 | minute: 分 | |
118 | month: 月 | |
119 | second: 秒 | |
120 | year: 年 | |
121 | errors: | |
122 | format: ! '%{attribute}%{message}' | |
123 | messages: | |
124 | accepted: を受諾してください。 | |
125 | blank: を入力してください。 | |
126 | present: は入力しないでください。 | |
127 | confirmation: と%{attribute}の入力が一致しません。 | |
128 | empty: を入力してください。 | |
129 | equal_to: は%{count}にしてください。 | |
130 | even: は偶数にしてください。 | |
131 | exclusion: は予約されています。 | |
132 | greater_than: は%{count}より大きい値にしてください。 | |
133 | greater_than_or_equal_to: は%{count}以上の値にしてください。 | |
134 | inclusion: は一覧にありません。 | |
135 | invalid: は不正な値です。 | |
136 | less_than: は%{count}より小さい値にしてください。 | |
137 | less_than_or_equal_to: は%{count}以下の値にしてください。 | |
138 | not_a_number: は数値で入力してください。 | |
139 | not_an_integer: は整数で入力してください。 | |
140 | odd: は奇数にしてください。 | |
141 | record_invalid: バリデーションに失敗しました。 %{errors} | |
142 | restrict_dependent_destroy: ! '%{record}が存在しているので削除できません。' | |
143 | taken: はすでに存在します。 | |
144 | too_long: は%{count}文字以内で入力してください。 | |
145 | too_short: は%{count}文字以上で入力してください。 | |
146 | wrong_length: は%{count}文字で入力してください。 | |
147 | other_than: "は%{count}以外の値にしてください。" | |
148 | template: | |
149 | body: 次の項目を確認してください。 | |
150 | header: | |
151 | one: ! '%{model}にエラーが発生しました。' | |
152 | other: ! '%{model}に%{count}個のエラーが発生しました。' | |
153 | helpers: | |
154 | select: | |
155 | prompt: 選択してください。 | |
156 | submit: | |
157 | create: 登録する | |
158 | submit: 保存する | |
159 | update: 更新する | |
160 | number: | |
161 | currency: | |
162 | format: | |
163 | delimiter: ! ',' | |
164 | format: ! '%n%u' | |
165 | precision: 0 | |
166 | separator: . | |
167 | significant: false | |
168 | strip_insignificant_zeros: false | |
169 | unit: 円 | |
170 | format: | |
171 | delimiter: ! ',' | |
172 | precision: 3 | |
173 | separator: . | |
174 | significant: false | |
175 | strip_insignificant_zeros: false | |
176 | human: | |
177 | decimal_units: | |
178 | format: ! '%n %u' | |
179 | units: | |
180 | billion: 十億 | |
181 | million: 百万 | |
182 | quadrillion: 千兆 | |
183 | thousand: 千 | |
184 | trillion: 兆 | |
185 | unit: '' | |
186 | format: | |
187 | delimiter: '' | |
188 | precision: 3 | |
189 | significant: true | |
190 | strip_insignificant_zeros: true | |
191 | storage_units: | |
192 | format: ! '%n%u' | |
193 | units: | |
194 | byte: バイト | |
195 | gb: ギガバイト | |
196 | kb: キロバイト | |
197 | mb: メガバイト | |
198 | tb: テラバイト | |
199 | percentage: | |
200 | format: | |
201 | delimiter: '' | |
202 | format: "%n%" | |
203 | precision: | |
204 | format: | |
205 | delimiter: '' | |
206 | support: | |
207 | array: | |
208 | last_word_connector: と | |
209 | two_words_connector: と | |
210 | words_connector: と | |
211 | time: | |
212 | am: 午前 | |
213 | formats: | |
214 | default: ! '%Y/%m/%d %H:%M:%S' | |
215 | long: ! '%Y年%m月%d日(%a) %H時%M分%S秒 %z' | |
216 | short: ! '%y/%m/%d %H:%M' | |
217 | pm: 午後 | |
@@ -22,3 +22,196 @@ ja: |
6 | 6 | # GET /tweets.json |
7 | 7 | def index |
8 | 8 | @tweets = Tweet.all |
9 | @tweet = Tweet.new | |
9 | 10 | end |
10 | 11 | |
11 | 12 | # GET /tweets/1 |
@@ -6,6 +6,7 @@ class TweetsController < ApplicationController |
27 | 27 | フォロワー |
28 | 28 | .num |
29 | 29 | 0 |
30 | = form_for @tweet do |f| | |
31 | .form-group | |
32 | = f.text_area :content, class: "form-control" | |
33 | = f.submit "つぶやく", class: "btn btn-success" | |
30 | 34 | .col-xs-8.right-content |
31 | 35 | .list-group |
32 | 36 | = div_for @tweets, class: "list-group-item" do |t| |
@@ -27,6 +27,10 @@ |
105 | 105 | color: #777 |
106 | 106 | .num |
107 | 107 | font-size: 18px |
108 | .new_tweet | |
109 | margin-top: 20px | |
110 | textarea | |
111 | width: 100% !important | |
112 | .btn | |
113 | width: 100% | |
108 | 114 | .right-content |
109 | 115 | .list-group-item:last-child |
110 | 116 | border-bottom-width: 3px |
@@ -105,6 +105,12 @@ html, body |
31 | 31 | |
32 | 32 | respond_to do |format| |
33 | 33 | if @tweet.save |
34 | format.html { redirect_to @tweet, notice: 'Tweet was successfully created.' } | |
34 | format.html { redirect_to tweets_url, notice: 'Tweet was successfully created.' } | |
35 | 35 | format.json { render :show, status: :created, location: @tweet } |
36 | 36 | else |
37 | 37 | format.html { render :new } |
@@ -31,7 +31,7 @@ def create |
34 | 34 | format.html { redirect_to tweets_url, notice: 'Tweet was successfully created.' } |
35 | 35 | format.json { render :show, status: :created, location: @tweet } |
36 | 36 | else |
37 | format.html { render :new } | |
37 | @tweets = Tweet.all | |
38 | format.html { render :index } | |
38 | 39 | format.json { render json: @tweet.errors, status: :unprocessable_entity } |
39 | 40 | end |
40 | 41 | end |
@@ -34,7 +34,8 @@ def create |
27 | 27 | フォロワー |
28 | 28 | .num |
29 | 29 | 0 |
30 | - @tweet.errors.full_messages.each do |message| | |
31 | .alert.alert-danger= message | |
30 | 32 | = form_for @tweet do |f| |
31 | 33 | .form-group |
32 | 34 | = f.text_area :content, class: "form-control" |
@@ -27,6 +27,8 @@ |
3 | 3 | |
4 | 4 | validates :user, presence: true |
5 | 5 | validates :content, presence: true, length: { in: 1..140 } |
6 | ||
7 | default_scope -> { order(created_at: :desc) } | |
6 | 8 | end |
@@ -3,4 +3,6 @@ class Tweet < ActiveRecord::Base |
34 | 34 | = f.text_area :content, class: "form-control" |
35 | 35 | = f.submit "つぶやく", class: "btn btn-success" |
36 | 36 | .col-xs-8.right-content |
37 | - if notice | |
38 | .alert.alert-info= notice | |
37 | 39 | .list-group |
38 | 40 | = div_for @tweets, class: "list-group-item" do |t| |
39 | 41 | %h4.user |
@@ -34,6 +34,8 @@ |
8 | 8 | @#{@user.name} |
9 | 9 | .bio |
10 | 10 | = @user.bio |
11 | ||
12 | %ul.nav.nav-tabs.nav-justified | |
13 | %li.active | |
14 | = link_to user_path(@user) do | |
15 | .text | |
16 | つぶやき | |
17 | .num | |
18 | #{@user.tweets.count} | |
19 | %li | |
20 | = link_to nil do | |
21 | .text | |
22 | フォロー | |
23 | .num | |
24 | 0 | |
25 | %li | |
26 | = link_to nil do | |
27 | .text | |
28 | フォロワー | |
29 | .num | |
30 | 0 | |
31 | %li | |
32 | = link_to nil do | |
33 | .text | |
34 | お気に入り | |
35 | .num | |
36 | 0 | |
37 | ||
38 | .list-group | |
39 | - if @user.tweets.empty? | |
40 | .list-group-item | |
41 | まだツイートはありません | |
42 | = div_for @user.tweets, class: "list-group-item" do |t| | |
43 | %h4.user | |
44 | %span.user-name | |
45 | = link_to t.user.name, user_path(t.user) | |
46 | %span.user-id | |
47 | @#{t.user.name} | |
48 | %span.time.pull-right | |
49 | = distance_of_time_in_words_to_now(t.created_at) | |
50 | .clear | |
51 | .tweet-content | |
52 | %p | |
53 | = t.content | |
@@ -8,3 +8,46 @@ |
1 | 1 | class RegistrationsController < ApplicationController |
2 | 2 | def new |
3 | 3 | @user = User.new |
4 | redirect_to tweets_url if logged_in? | |
4 | 5 | end |
5 | 6 | |
6 | 7 | def create |
@@ -1,6 +1,7 @@ |
1 | 1 | class SessionsController < ApplicationController |
2 | 2 | def new |
3 | 3 | @user = User.new |
4 | redirect_to tweets_url if logged_in? | |
4 | 5 | end |
5 | 6 | |
6 | 7 | def create |
@@ -1,6 +1,7 @@ |
8 | 8 | |
9 | 9 | if @user.save |
10 | 10 | login(@user.email, @user.password) |
11 | redirect_to root_url | |
11 | redirect_to tweets_url | |
12 | 12 | else |
13 | 13 | render :new |
14 | 14 | end |
@@ -8,7 +8,7 @@ def create |
8 | 8 | password = params_user[:password] |
9 | 9 | |
10 | 10 | if login(email, password) |
11 | redirect_to root_url, notice: "サインインしました" | |
11 | redirect_to tweets_url, notice: "サインインしました" | |
12 | 12 | else |
13 | 13 | @user = User.new(email: email) |
14 | 14 | render :new |
@@ -8,7 +8,7 @@ def create |
$ rails g model favorite user_id:integer tweet_id:integer
5 | 5 | t.integer :tweet_id |
6 | 6 | |
7 | 7 | t.timestamps |
8 | ||
9 | t.index :user_id | |
10 | t.index :tweet_id | |
11 | t.index :created_at | |
8 | 12 | end |
9 | 13 | end |
10 | 14 | end |
@@ -5,6 +5,10 @@ def change |
$ rake db:migrate
4 | 4 | resource :sessions, only: [:new, :create, :destroy] |
5 | 5 | resource :settings, only: [:edit, :update] |
6 | 6 | resources :users, only: [:index, :show] |
7 | resources :tweets | |
7 | resources :tweets do | |
8 | resource :favorites, only: [:create, :destroy] | |
9 | end | |
8 | 10 | |
9 | 11 | root to: 'registrations#new' |
10 | 12 | |
@@ -4,7 +4,9 @@ |
3 | 3 | resource :registrations, only: [:new, :create] |
4 | 4 | resource :sessions, only: [:new, :create, :destroy] |
5 | 5 | resource :settings, only: [:edit, :update] |
6 | resources :users, only: [:index, :show] | |
6 | ||
7 | resources :users, only: [:index, :show] do | |
8 | get :favorites, on: :member | |
9 | end | |
10 | ||
7 | 11 | resources :tweets do |
8 | 12 | resource :favorites, only: [:create, :destroy] |
9 | 13 | end |
@@ -3,7 +3,11 @@ |
1 | class FavoritesController < ApplicationController | |
2 | end | |
@@ -0,0 +1,2 @@ |
1 | 1 | class FavoritesController < ApplicationController |
2 | before_filter :require_login | |
3 | ||
4 | def create | |
5 | @tweet = Tweet.find(params[:tweet_id]) | |
6 | @favorite = current_user.favorites.build(tweet: @tweet) | |
7 | ||
8 | if @favorite.save | |
9 | redirect_to tweets_url, notice: "お気に入りに登録しました" | |
10 | else | |
11 | redirect_to tweets_url, alert: "このツイートはお気に入りに登録できません" | |
12 | end | |
13 | end | |
2 | 14 | end |
@@ -1,2 +1,14 @@ |
11 | 11 | redirect_to tweets_url, alert: "このツイートはお気に入りに登録できません" |
12 | 12 | end |
13 | 13 | end |
14 | ||
15 | def destroy | |
16 | @favorite = current_user.favorites.find_by!(tweet_id: params[:tweet_id]) | |
17 | @favorite.destroy | |
18 | redirect_to tweets_url, notice: "お気に入りを解除しました" | |
19 | end | |
14 | 20 | end |
@@ -11,4 +11,10 @@ def create |
12 | 12 | def show |
13 | 13 | @user = User.find(params[:id]) |
14 | 14 | end |
15 | ||
16 | def favorites | |
17 | @user = User.find(params[:id]) | |
18 | end | |
15 | 19 | end |
@@ -12,4 +12,8 @@ def index |
1 | 1 | class Favorite < ActiveRecord::Base |
2 | belongs_to :user | |
3 | belongs_to :tweet | |
2 | 4 | end |
@@ -1,2 +1,4 @@ |
1 | 1 | class Tweet < ActiveRecord::Base |
2 | 2 | belongs_to :user |
3 | has_many :favorites, dependent: :destroy | |
3 | 4 | |
4 | 5 | validates :user, presence: true |
5 | 6 | validates :content, presence: true, length: { in: 1..140 } |
@@ -1,5 +1,6 @@ |
2 | 2 | authenticates_with_sorcery! |
3 | 3 | |
4 | 4 | has_many :tweets, dependent: :destroy |
5 | has_many :favorites, dependent: :destroy | |
5 | 6 | |
6 | 7 | validates :name, presence: true, uniqueness: { case_sensitive: false }, format: { with: /\A[a-z][a-z0-9]+\z/ }, length: { in: 4..24 } |
7 | 8 | validates :screen_name, length: { maximum: 140 } |
@@ -2,6 +2,7 @@ class User < ActiveRecord::Base |
1 | 1 | class Favorite < ActiveRecord::Base |
2 | 2 | belongs_to :user |
3 | 3 | belongs_to :tweet |
4 | ||
5 | validates :user, presence: true | |
6 | validates :user_id, uniqueness: { scope: :tweet_id } | |
7 | validates :tweet, presence: true | |
4 | 8 | end |
@@ -1,4 +1,8 @@ |
4 | 4 | |
5 | 5 | validates :user, presence: true |
6 | 6 | validates :content, presence: true, length: { in: 1..140 } |
7 | ||
8 | def favorited_by? user | |
9 | favorites.where(user_id: user.id).exists? | |
10 | end | |
7 | 11 | end |
@@ -4,4 +4,8 @@ class Tweet < ActiveRecord::Base |
49 | 49 | .tweet-content |
50 | 50 | %p |
51 | 51 | = t.content |
52 | .content-footer | |
53 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post | |
@@ -49,3 +49,5 @@ |
50 | 50 | %p |
51 | 51 | = t.content |
52 | 52 | .content-footer |
53 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post | |
53 | - if t.favorited_by? current_user | |
54 | = link_to "お気に入りの解除", tweet_favorites_path(t), method: :delete | |
55 | - else | |
56 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post | |
@@ -50,4 +50,7 @@ |
1 | _header.html.haml | |
2 | .user-info | |
3 | - if notice | |
4 | .alert.alert-info= notice | |
5 | %span.user-name | |
6 | = render_user_screen_name(@user) | |
7 | %span.user-id | |
8 | @#{@user.name} | |
9 | .bio | |
10 | = @user.bio | |
11 | ||
12 | %ul.nav.nav-tabs.nav-justified | |
13 | %li.active | |
14 | = link_to user_path(@user) do | |
15 | .text | |
16 | つぶやき | |
17 | .num | |
18 | #{@user.tweets.count} | |
19 | %li | |
20 | = link_to nil do | |
21 | .text | |
22 | フォロー | |
23 | .num | |
24 | 0 | |
25 | %li | |
26 | = link_to nil do | |
27 | .text | |
28 | フォロワー | |
29 | .num | |
30 | 0 | |
31 | %li | |
32 | = link_to nil do | |
33 | .text | |
34 | お気に入り | |
35 | .num | |
36 | 0 | |
@@ -1,0 +1,35 @@ |
1 | 1 | .col-xs-8#users-content |
2 | .user-info | |
3 | - if notice | |
4 | .alert.alert-info= notice | |
5 | %span.user-name | |
6 | = render_user_screen_name(@user) | |
7 | %span.user-id | |
8 | @#{@user.name} | |
9 | .bio | |
10 | = @user.bio | |
11 | ||
12 | %ul.nav.nav-tabs.nav-justified | |
13 | %li.active | |
14 | = link_to user_path(@user) do | |
15 | .text | |
16 | つぶやき | |
17 | .num | |
18 | #{@user.tweets.count} | |
19 | %li | |
20 | = link_to nil do | |
21 | .text | |
22 | フォロー | |
23 | .num | |
24 | 0 | |
25 | %li | |
26 | = link_to nil do | |
27 | .text | |
28 | フォロワー | |
29 | .num | |
30 | 0 | |
31 | %li | |
32 | = link_to nil do | |
33 | .text | |
34 | お気に入り | |
35 | .num | |
36 | 0 | |
37 | 2 | |
38 | 3 | .list-group |
39 | 4 | - if @user.tweets.empty? |
@@ -1,39 +1,4 @@ |
28 | 28 | .num |
29 | 29 | 0 |
30 | 30 | %li |
31 | = link_to nil do | |
31 | = link_to favorites_user_path(@user) do | |
32 | 32 | .text |
33 | 33 | お気に入り |
34 | 34 | .num |
@@ -28,7 +28,7 @@ |
1 | 1 | .col-xs-8#users-content |
2 | ||
2 | = render partial: "users/header" | |
3 | 3 | .list-group |
4 | 4 | - if @user.tweets.empty? |
5 | 5 | .list-group-item |
@@ -1,5 +1,5 @@ |
9 | 9 | = @user.bio |
10 | 10 | |
11 | 11 | %ul.nav.nav-tabs.nav-justified |
12 | %li.active | |
12 | %li{ class: action_name == "show" ? "active" : nil } | |
13 | 13 | = link_to user_path(@user) do |
14 | 14 | .text |
15 | 15 | つぶやき |
@@ -9,7 +9,7 @@ | ||
27 | 27 | フォロワー |
28 | 28 | .num |
29 | 29 | 0 |
30 | %li | |
30 | %li{ class: action_name == "favorites" ? "active" : nil } | |
31 | 31 | = link_to favorites_user_path(@user) do |
32 | 32 | .text |
33 | 33 | お気に入り |
@@ -27,7 +27,7 @@ |
1 | _tweet.html.haml | |
1 | = div_for @user.tweets, class: "list-group-item" do |t| | |
2 | %h4.user | |
3 | %span.user-name | |
4 | = link_to t.user.name, user_path(t.user) | |
5 | %span.user-id | |
6 | @#{t.user.name} | |
7 | %span.time.pull-right | |
8 | = distance_of_time_in_words_to_now(t.created_at) | |
9 | .clear | |
10 | .tweet-content | |
11 | %p | |
12 | = t.content | |
@@ -1,0 +1,12 @@ |
4 | 4 | - if @user.tweets.empty? |
5 | 5 | .list-group-item |
6 | 6 | まだツイートはありません |
7 | = div_for @user.tweets, class: "list-group-item" do |t| | |
8 | %h4.user | |
9 | %span.user-name | |
10 | = link_to t.user.name, user_path(t.user) | |
11 | %span.user-id | |
12 | @#{t.user.name} | |
13 | %span.time.pull-right | |
14 | = distance_of_time_in_words_to_now(t.created_at) | |
15 | .clear | |
16 | .tweet-content | |
17 | %p | |
18 | = t.content | |
@@ -4,15 +4,3 @@ |
1 | = div_for @user.tweets, class: "list-group-item" do |t| | |
1 | = div_for tweet, class: "list-group-item" do |t| | |
2 | 2 | %h4.user |
3 | 3 | %span.user-name |
4 | 4 | = link_to t.user.name, user_path(t.user) |
@@ -1,4 +1,4 @@ |
4 | 4 | - if @user.tweets.empty? |
5 | 5 | .list-group-item |
6 | 6 | まだツイートはありません |
7 | - @user.tweets.each do |tweet| | |
8 | = render partial: "users/tweet", object: tweet | |
7 | = render partial: "users/tweet", collection: @user.tweets | |
@@ -4,5 +4,4 @@ |
.col-xs-8#users-content
= render partial: "users/header"
.list-group
- if @user.favorites.empty?
.list-group-item
まだお気に入りに登録されたツイートはありません
= render partial: "users/tweet", collection: @user.favorites.map{|f| f.tweet}
$ rails g model follow follower_id:integer inverse_follower_id:integer
5 | 5 | t.integer :inverse_follower_id |
6 | 6 | |
7 | 7 | t.timestamps |
8 | ||
9 | t.index :follower_id | |
10 | t.index :inverse_follower_id | |
8 | 11 | end |
9 | 12 | end |
10 | 13 | end |
@@ -5,6 +5,9 @@ def change |
$ rake db:migrate
5 | 5 | resource :settings, only: [:edit, :update] |
6 | 6 | |
7 | 7 | resources :users, only: [:index, :show] do |
8 | resource :follows, only: [:create, :destroy] | |
8 | 9 | get :favorites, on: :member |
9 | 10 | end |
10 | 11 | |
@@ -5,6 +5,7 @@ |
7 | 7 | resources :users, only: [:index, :show] do |
8 | 8 | resource :follows, only: [:create, :destroy] |
9 | 9 | get :favorites, on: :member |
10 | get :follows, on: :member | |
10 | 11 | end |
11 | 12 | |
12 | 13 | resources :tweets do |
@@ -7,6 +7,7 @@ |
8 | 8 | resource :follows, only: [:create, :destroy] |
9 | 9 | get :favorites, on: :member |
10 | 10 | get :follows, on: :member |
11 | get :followers, on: :member | |
11 | 12 | end |
12 | 13 | |
13 | 14 | resources :tweets do |
@@ -8,6 +8,7 @@ |
13 | 13 | |
14 | 14 | resources :tweets do |
15 | 15 | resource :favorites, only: [:create, :destroy] |
16 | get :timeline, on: :collection | |
16 | 17 | end |
17 | 18 | |
18 | 19 | root to: 'registrations#new' |
@@ -13,6 +13,7 @@ |
1 | class FollowsController < ApplicationController | |
2 | end | |
@@ -0,0 +1,2 @@ |
1 | 1 | class FollowsController < ApplicationController |
2 | before_filter :require_login | |
3 | ||
4 | def create | |
5 | @user = User.find(params[:user_id]) | |
6 | ||
7 | if @user.inverse_follows.create(follower: current_user) | |
8 | redirect_to tweets_url, notice: "フォローしました" | |
9 | else | |
10 | redirect_to tweets_url, alert: "フォローできません" | |
11 | end | |
12 | end | |
2 | 13 | end |
@@ -1,2 +1,13 @@ |
10 | 10 | redirect_to tweets_url, alert: "フォローできません" |
11 | 11 | end |
12 | 12 | end |
13 | ||
14 | def destroy | |
15 | @user = User.find(params[:user_id]) | |
16 | follow = @user.inverse_follows.find_by(follower: current_user.id) | |
17 | follow.destroy | |
18 | redirect_to tweets_url, notice: "フォローを解除しました" | |
19 | end | |
13 | 20 | end |
@@ -10,4 +10,11 @@ def create |
16 | 16 | def favorites |
17 | 17 | @user = User.find(params[:id]) |
18 | 18 | end |
19 | ||
20 | def follows | |
21 | @user = User.find(params[:id]) | |
22 | end | |
19 | 23 | end |
@@ -16,4 +16,8 @@ def show |
20 | 20 | def follows |
21 | 21 | @user = User.find(params[:id]) |
22 | 22 | end |
23 | ||
24 | def followers | |
25 | @user = User.find(params[:id]) | |
26 | end | |
23 | 27 | end |
@@ -20,4 +20,8 @@ def favorites |
9 | 9 | @tweet = Tweet.new |
10 | 10 | end |
11 | 11 | |
12 | def timeline | |
13 | @tweets = Tweet.eager_load(user: :inverse_follows).where(follows: { follower_id: current_user.id }) | |
14 | @tweet = Tweet.new | |
15 | end | |
16 | ||
12 | 17 | # GET /tweets/1 |
13 | 18 | # GET /tweets/1.json |
14 | 19 | def show |
@@ -9,6 +9,11 @@ def index |
1 | 1 | class Follow < ActiveRecord::Base |
2 | belongs_to :follower, class_name: User | |
3 | belongs_to :inverse_follower, class_name: User | |
2 | 4 | end |
@@ -1,2 +1,4 @@ |
4 | 4 | has_many :tweets, dependent: :destroy |
5 | 5 | has_many :favorites, dependent: :destroy |
6 | 6 | |
7 | has_many :follows, foreign_key: :follower_id | |
8 | has_many :inverse_followers, through: :follows | |
9 | has_many :inverse_follows, foreign_key: :inverse_follower_id, class_name: Follow | |
10 | has_many :followers, through: :inverse_follows | |
11 | ||
7 | 12 | validates :name, presence: true, uniqueness: { case_sensitive: false }, format: { with: /\A[a-z][a-z0-9]+\z/ }, length: { in: 4..24 } |
8 | 13 | validates :screen_name, length: { maximum: 140 } |
9 | 14 | validates :bio, length: { maximum: 200 } |
@@ -4,6 +4,11 @@ class User < ActiveRecord::Base |
1 | 1 | class Follow < ActiveRecord::Base |
2 | 2 | belongs_to :follower, class_name: User |
3 | 3 | belongs_to :inverse_follower, class_name: User |
4 | ||
5 | validates :follower, presence: true | |
6 | validates :inverse_follower, presence: true | |
7 | validates :inverse_follower_id, uniqueness: { scope: :follower_id } | |
4 | 8 | end |
@@ -1,4 +1,8 @@ |
15 | 15 | validates :email, presence: true, uniqueness: { case_sensitive: false } |
16 | 16 | validates :password, confirmation: true, length: { in: 6..24 }, if: :password |
17 | 17 | validates :password_confirmation, presence: true, if: :password |
18 | ||
19 | def followed_by? user | |
20 | inverse_follows.where(follower_id: user.id).exists? | |
21 | end | |
18 | 22 | end |
@@ -15,4 +15,8 @@ class User < ActiveRecord::Base |
54 | 54 | = link_to "お気に入りの解除", tweet_favorites_path(t), method: :delete |
55 | 55 | - else |
56 | 56 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post |
57 | - if t.user.followed_by? current_user | |
58 | = link_to "フォロー解除", user_follows_path(t.user), method: :delete | |
59 | - else | |
60 | = link_to "フォロー", user_follows_path(t.user), method: :post | |
@@ -54,3 +54,7 @@ |
16 | 16 | .num |
17 | 17 | #{@user.tweets.count} |
18 | 18 | %li |
19 | = link_to nil do | |
19 | = link_to follows_user_path(@user) do | |
20 | 20 | .text |
21 | 21 | フォロー |
22 | 22 | .num |
@@ -16,7 +16,7 @@ |
1 | .col-xs-8#users-content | |
2 | = render partial: "users/header" | |
3 | .list-group | |
@@ -0,0 +1,3 @@ |
1 | = div_for user, class: "list-group-item" do |u| | |
2 | %h4.user | |
3 | %span.user-name | |
4 | = link_to u.name, user_path(u) | |
5 | %span.user-id | |
6 | @#{u.name} | |
7 | .bio | |
8 | = u.bio | |
9 | .follow-unfollow | |
10 | - if u.followed_by? current_user | |
11 | = link_to "フォロー解除", user_follows_path(u), method: :delete | |
12 | - else | |
13 | = link_to "フォロー", user_follows_path(u), method: :post | |
@@ -0,0 +1,13 @@ |
1 | 1 | .col-xs-8#users-content |
2 | 2 | = render partial: "users/header" |
3 | 3 | .list-group |
4 | = render @user.inverse_followers | |
@@ -1,3 +1,4 @@ |
22 | 22 | .num |
23 | 23 | 0 |
24 | 24 | %li |
25 | = link_to nil do | |
25 | = link_to followers_user_path(@user) do | |
26 | 26 | .text |
27 | 27 | フォロワー |
28 | 28 | .num |
@@ -22,7 +22,7 @@ |
1 | .col-xs-8#users-content | |
2 | = render partial: "users/header" | |
3 | .list-group | |
4 | = render @user.inverse_followers | |
@@ -0,0 +1,4 @@ |
1 | 1 | .col-xs-8#users-content |
2 | 2 | = render partial: "users/header" |
3 | 3 | .list-group |
4 | = render @user.inverse_followers | |
4 | = render @user.followers | |
@@ -1,4 +1,4 @@ |
15 | 15 | つぶやき |
16 | 16 | .num |
17 | 17 | #{@user.tweets.count} |
18 | %li | |
18 | %li{ class: action_name == "follows" ? "active" : nil } | |
19 | 19 | = link_to follows_user_path(@user) do |
20 | 20 | .text |
21 | 21 | フォロー |
22 | 22 | .num |
23 | 23 | 0 |
24 | %li | |
24 | %li{ class: action_name == "followers" ? "active" : nil } | |
25 | 25 | = link_to followers_user_path(@user) do |
26 | 26 | .text |
27 | 27 | フォロワー |
@@ -15,13 +15,13 @@ |
20 | 20 | .text |
21 | 21 | フォロー |
22 | 22 | .num |
23 | 0 | |
23 | #{@user.inverse_followers.count} | |
24 | 24 | %li{ class: action_name == "followers" ? "active" : nil } |
25 | 25 | = link_to followers_user_path(@user) do |
26 | 26 | .text |
27 | 27 | フォロワー |
28 | 28 | .num |
29 | 0 | |
29 | #{@user.followers.count} | |
30 | 30 | %li{ class: action_name == "favorites" ? "active" : nil } |
31 | 31 | = link_to favorites_user_path(@user) do |
32 | 32 | .text |
33 | 33 | お気に入り |
34 | 34 | .num |
35 | 0 | |
35 | #{@user.favorites.count} | |
@@ -20,16 +20,16 @@ |
2 | 2 | .list-group |
3 | 3 | .list-group-item.user-list |
4 | 4 | %h2 ユーザー一覧 |
5 | = div_for @users, class: "list-group-item" do |u| | |
6 | %h4.user | |
7 | %span.user-name | |
8 | = link_to render_user_screen_name(u), user_path(u) | |
9 | %span.user-id | |
10 | @#{u.name} | |
11 | .bio | |
12 | = u.bio | |
5 | = render partial: "users/user", collection: @users | |
@@ -2,11 +2,4 @@ |
21 | 21 | .text |
22 | 22 | フォロー |
23 | 23 | .num |
24 | 0 | |
24 | = link_to current_user.inverse_followers.count, follows_user_path(current_user) | |
25 | 25 | .col-xs-4.follower-num |
26 | 26 | .text |
27 | 27 | フォロワー |
28 | 28 | .num |
29 | 0 | |
29 | = link_to current_user.followers.count, followers_user_path(current_user) | |
30 | 30 | - @tweet.errors.full_messages.each do |message| |
31 | 31 | .alert.alert-danger= message |
32 | 32 | = form_for @tweet do |f| |
@@ -21,12 +21,12 @@ |
1 | _panel.html.haml | |
1 | - if logged_in? | |
2 | .panel.panel-default | |
3 | .panel-body | |
4 | = link_to user_path(current_user), class: "user" do | |
5 | %span.user-name | |
6 | = render_user_screen_name current_user | |
7 | %span.user-id | |
8 | @#{current_user.name} | |
9 | .user-activity | |
10 | .row | |
11 | .col-xs-4.tweets-num | |
12 | .text | |
13 | つぶやき | |
14 | .num | |
15 | = link_to current_user.tweets.count, user_path(current_user) | |
16 | .col-xs-4.follow-num | |
17 | .text | |
18 | フォロー | |
19 | .num | |
20 | = link_to current_user.inverse_followers.count, follows_user_path(current_user) | |
21 | .col-xs-4.follower-num | |
22 | .text | |
23 | フォロワー | |
24 | .num | |
25 | = link_to current_user.followers.count, followers_user_path(current_user) | |
26 | - @tweet.errors.full_messages.each do |message| | |
27 | .alert.alert-danger= message | |
28 | = form_for @tweet do |f| | |
29 | .form-group | |
30 | = f.text_area :content, class: "form-control" | |
31 | = f.submit "つぶやく", class: "btn btn-success" | |
@@ -1,0 +1,31 @@ |
2 | 2 | .container |
3 | 3 | .row |
4 | 4 | .col-xs-4.left-content |
5 | - if logged_in? | |
6 | .panel.panel-default | |
7 | .panel-body | |
8 | = link_to user_path(current_user), class: "user" do | |
9 | %span.user-name | |
10 | = render_user_screen_name current_user | |
11 | %span.user-id | |
12 | @#{current_user.name} | |
13 | .user-activity | |
14 | .row | |
15 | .col-xs-4.tweets-num | |
16 | .text | |
17 | つぶやき | |
18 | .num | |
19 | = link_to current_user.tweets.count, user_path(current_user) | |
20 | .col-xs-4.follow-num | |
21 | .text | |
22 | フォロー | |
23 | .num | |
24 | = link_to current_user.inverse_followers.count, follows_user_path(current_user) | |
25 | .col-xs-4.follower-num | |
26 | .text | |
27 | フォロワー | |
28 | .num | |
29 | = link_to current_user.followers.count, followers_user_path(current_user) | |
30 | - @tweet.errors.full_messages.each do |message| | |
31 | .alert.alert-danger= message | |
32 | = form_for @tweet do |f| | |
33 | .form-group | |
34 | = f.text_area :content, class: "form-control" | |
35 | = f.submit "つぶやく", class: "btn btn-success" | |
36 | 5 | .col-xs-8.right-content |
37 | 6 | - if notice |
38 | 7 | .alert.alert-info= notice |
@@ -2,37 +2,6 @@ |
2 | 2 | .container |
3 | 3 | .row |
4 | 4 | .col-xs-4.left-content |
5 | = render partial: "panel" | |
5 | 6 | .col-xs-8.right-content |
6 | 7 | - if notice |
7 | 8 | .alert.alert-info= notice |
@@ -2,6 +2,7 @@ |
19 | 19 | .tweet-content |
20 | 20 | %p |
21 | 21 | = t.content |
22 | .content-footer | |
23 | - if t.favorited_by? current_user | |
24 | = link_to "お気に入りの解除", tweet_favorites_path(t), method: :delete | |
25 | - else | |
26 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post | |
27 | - if t.user.followed_by? current_user | |
28 | = link_to "フォロー解除", user_follows_path(t.user), method: :delete | |
29 | - else | |
30 | = link_to "フォロー", user_follows_path(t.user), method: :post | |
@@ -19,12 +19,3 @@ |
10 | 10 | .tweet-content |
11 | 11 | %p |
12 | 12 | = t.content |
13 | .content-footer | |
14 | - if t.favorited_by? current_user | |
15 | = link_to "お気に入りの解除", tweet_favorites_path(t), method: :delete | |
16 | - else | |
17 | = link_to "お気に入りに登録", tweet_favorites_path(t), method: :post | |
18 | - if t.user.followed_by? current_user | |
19 | = link_to "フォロー解除", user_follows_path(t.user), method: :delete | |
20 | - else | |
21 | = link_to "フォロー", user_follows_path(t.user), method: :post | |
@@ -10,3 +10,12 @@ |
7 | 7 | - if notice |
8 | 8 | .alert.alert-info= notice |
9 | 9 | .list-group |
10 | = div_for @tweets, class: "list-group-item" do |t| | |
11 | %h4.user | |
12 | %span.user-name | |
13 | = link_to render_user_screen_name(t.user), user_path(t.user) | |
14 | %span.user-id | |
15 | @#{t.user.name} | |
16 | %span.time.pull-right | |
17 | = distance_of_time_in_words_to_now(t.created_at) | |
18 | .clear | |
19 | .tweet-content | |
20 | %p | |
21 | = t.content | |
10 | = render partial: "users/tweet", collection: @tweets | |
@@ -7,15 +7,4 @@ |
1 | #tweets-content | |
2 | .container | |
3 | .row | |
4 | .col-xs-4.left-content | |
5 | = render partial: "panel" | |
6 | .col-xs-8.right-content | |
7 | - if notice | |
8 | .alert.alert-info= notice | |
9 | .list-group | |
10 | = render partial: "users/tweet", collection: @tweets | |
@@ -0,0 +1,10 @@ |
7 | 7 | - if notice |
8 | 8 | .alert.alert-info= notice |
9 | 9 | .list-group |
10 | .list-group-item | |
11 | .btn-group | |
12 | = link_to "すべてのつぶやき", tweets_path, class: "active btn btn-primary" | |
13 | = link_to "フォローしている人のつぶやき", timeline_tweets_path, class: "btn btn-default" | |
10 | 14 | = render partial: "users/tweet", collection: @tweets |
@@ -7,4 +7,8 @@ |
7 | 7 | - if notice |
8 | 8 | .alert.alert-info= notice |
9 | 9 | .list-group |
10 | .list-group-item | |
11 | .btn-group | |
12 | = link_to "すべてのつぶやき", tweets_path, class: "active btn btn-primary" | |
13 | = link_to "フォローしている人のつぶやき", timeline_tweets_path, class: "btn btn-default" | |
10 | 14 | = render partial: "users/tweet", collection: @tweets |
@@ -7,4 +7,8 @@ |
6 | 6 | @favorite = current_user.favorites.build(tweet: @tweet) |
7 | 7 | |
8 | 8 | if @favorite.save |
9 | redirect_to tweets_url, notice: "お気に入りに登録しました" | |
9 | redirect_to request.referer, notice: "お気に入りに登録しました" | |
10 | 10 | else |
11 | redirect_to tweets_url, alert: "このツイートはお気に入りに登録できません" | |
11 | redirect_to request.referer, alert: "このツイートはお気に入りに登録できません" | |
12 | 12 | end |
13 | 13 | end |
14 | 14 | |
15 | 15 | def destroy |
16 | 16 | @favorite = current_user.favorites.find_by!(tweet_id: params[:tweet_id]) |
17 | 17 | @favorite.destroy |
18 | redirect_to tweets_url, notice: "お気に入りを解除しました" | |
18 | redirect_to request.referer, notice: "お気に入りを解除しました" | |
19 | 19 | end |
20 | 20 | end |
@@ -6,15 +6,15 @@ def create |
5 | 5 | @user = User.find(params[:user_id]) |
6 | 6 | |
7 | 7 | if @user.inverse_follows.create(follower: current_user) |
8 | redirect_to tweets_url, notice: "フォローしました" | |
8 | redirect_to request.referer, notice: "フォローしました" | |
9 | 9 | else |
10 | redirect_to tweets_url, alert: "フォローできません" | |
10 | redirect_to request.referer, alert: "フォローできません" | |
11 | 11 | end |
12 | 12 | end |
13 | 13 | |
@@ -5,9 +5,9 @@ def create | ||
15 | 15 | @user = User.find(params[:user_id]) |
16 | 16 | follow = @user.inverse_follows.find_by(follower: current_user.id) |
17 | 17 | follow.destroy |
18 | redirect_to tweets_url, notice: "フォローを解除しました" | |
18 | redirect_to request.referer, notice: "フォローを解除しました" | |
19 | 19 | end |
20 | 20 | end |
@@ -15,6 +15,6 @@ def destroy |