読者です 読者をやめる 読者になる 読者になる

男女比はカレーと福神漬けと同じくらい

マサカリよろしくお願いします。

MacBook ProでCUDAのGPUモードが使えたり使えなかったりする話

MacBook ProでTheanoのGPUモードを使うために設定を済ませてimportするとエラーが発生。
GPUモードが使えない...??

>>> import theano
WARNING (theano.sandbox.cuda): CUDA is installed, but device gpu is not available
  (error: Unable to get the number of gpus available: CUDA driver version is insufficient for CUDA runtime version)

 

自分のmacのグラフィックスを確認すると
NVIDIA製ではないので使えないのは当たり前でした。

  チップセットのモデル: Intel Iris Graphics 6100  
  種類:  GPU  
  バス:  内蔵  
  VRAM(ダイナミック、最大):  1536 MB  
  製造元:  Intel (0x8086)

 

でも調べているとiMacではCUDAのGPUモードが使えている人はいる様子。
同じApple製品で違うメーカーのGPUが載ってるってこと?
なんでだろう。

ket-30.hatenablog.com

 

さらに調べているとこんな記事が

MacBook Pro現行モデルの技術仕様を見ると最上位機種のグラフィックスチップはIntel Iris Pro GraphicsとAMD Radeon R9 M370Xとなっており、NVIDIA GeForceは搭載されていません。

ですが、MacBook Pro (15-inch, Mid 2012) - 技術仕様を見ると、私が持っているMacBook Proは15インチ2.6GHzモデルなのでNVIDIA GeForce GT 650M、1GB GDDR5メモリが搭載されています。

GeForce GT 650M | NVIDIAには「プログラミング環境」の行に「CUDA」とあるのでCUDAが使えるようです。

引用: GeForce搭載の旧モデルMacBook ProでCUDAをセットアップする手順のメモ · hnakamur's blog at github

昔のMacBook ProではGeForceを選択できたみたい。

というわけでGeForceが載っているものと載っていないものを2011~2015年で調べてみました。

GeForceが載っている
  • Retina, 15-inch, Mid 2014
  • Retina, 15-inch, Early 2013
  • 15-inch, Mid 2012
GeForceが載ってない
  • Retina, 15-inch, Mid 2015
  • Retina, 13-inch, Early 2015
  • Retina, 13-inch, Mid 2014
  • Retina, 13-inch, Late 2013
  • Retina, 13-inch, Early 2013
  • Retina, 13-inch, Late 2012
  • 13-inch, Mid 2012
  • 17-inch, Late 2011
  • 13-inch, Late 2011
  • 15-inch, Late 2011
  • 17-inch, Early 2011
  • 15-inch, Early 2011
  • 13-inch, Early 2011

まとめ

MacBook ProでCUDAのGPUモードを使うなら2012~2014年モデルの15インチを買うべし。

 

その他のApple製品の技術仕様はこちらからどうぞ
アップル – サポート - 技術仕様

graphvizを使って木構造を可視化する関数を作ってみた

卒業研究で木構造を可視化させる必要があったので関数を作ってみました。

木構造・ノードクラスの属性は次のようになります。

Tree クラス
属性名 型,クラス 説明
root Node Treeの根ノード
Node クラス
属性名 型,クラス 説明
num int ノード番号
child Node 子ノード
brother Node 兄弟ノード(木構造で考えると右側のノード)
parent Node 親ノード

 

ソースコード

 

現在研究している自己生成ニューラル木に菖蒲の花のデータセットを学習させたものを可視化させるとこのようになりました。 f:id:euglena1215:20160930153903p:plain

関数を少し修正して花の種類で色分けするとこのようになりました。 f:id:euglena1215:20160930155224p:plain

 

木構造が可視化できると色々捗りますよね。

参考にさせていただきました

PythonからGraphvizを使う - Leaaaaaaaaaaaaarning
画像処理についてあれこれ: Graphvizでノードの塗りつぶし色を指定する

Railsでセキュリティのことを考えずに作ったwebアプリは脆弱性があるのか調べてみた(脆弱性検証編)

この続きです。 euglena1215.hatenablog.jp

検証方法が全く網羅的ではないということを踏まえた上でお読みください。

検証

XSS(クロスサイトスクリプティング)

方法

投稿フォームに以下のリンクに載っているXSSの例を片っ端から入力してみた。
XSS Filter Evasion Cheat Sheet - OWASP

結果

脆弱性は見つからなかった。

理由

rails3からデフォルトで文字列を出力するときにはエスケープされるようになっているため基本的にはXSSは通らない。

なので文字列をエスケープさせたくない場合には
<%= 文字列.html_safe %>
<%= raw 文字列 %>
<%== 文字列 %>
のどれかを使う。

qiita.com

この記事によると <%== を使うのがベストらしい。

SQLインジェクション

方法

検索フォームに ');-- と入力する

結果

SELECT "users"."id" FROM "users" WHERE (username LIKE '%');--%’)
というクエリが生成され、userの全件取得ができてしまう。ということは…

 


 

方法

検索フォームに’ AND password LIKE ‘password’);— と入力する

結果

SELECT "users"."id" FROM "users" WHERE (username LIKE '%’ AND password LIKE ‘password’);—%')
というクエリが発行されてpasswordが’password’のユーザが取得できる。
という風に利用者が任意のクエリを発行することができる。これは危ない。
※今回使用したDeviseは暗号化したパスワードをDBに保存しているのですぐにパスワードがバレるというわけではありません

普通に利用しているとユーザがアクセスできないデータにアクセスされる可能性がある。

対策

where("username LIKE '%"+username+"%’”)
where("username LIKE ?","%#{username}%") に変更する。

以下のように修正する。

# before
  # app/models/post.rb
  scope :by_body_like, ->(body){
    where("body LIKE '%"+body+"%'")
  }
  # app/models/user.rb
  scope :by_username_like, ->(username){
    where("username LIKE '%"+username+"%'")
  }
# after
  # app/models/post.rb
  scope :by_body_like, ->(body){
    where("body LIKE :body ESCAPE '\\'", { body: "%#{sanitize_sql_like(body)}%"})
  }
  # app/models/user.rb
  scope :by_username_like, ->(username){
    where("username LIKE :username ESCAPE '\\'", { username: "%#{sanitize_sql_like(username)}%"})
  }

検索でLIKE演算子ワイルドカードである_や%が使われてもいいようにエスケープする必要がある。
Rails 4.2.1以降にはsanitize_sql_likeメソッドが実装されているのでそれを使う。
sanitize_sql_like (ActiveRecord::Sanitization::ClassMethods) - APIdock

?を使うとSQLインジェクションを防ぐことができるということは分かったものの、なぜこれでSQLインジェクションが防げるのかよく分からなかった。
なので今度Active recordを読み解いていこうと思う。
Active record whereメソッド :
rails/query_methods.rb at 0399b71dab8b270b4e40b2aff99194a8b8f2596c · rails/rails · GitHub

これはActive recordのwhereメソッドの仕様ではなくSQLプレースホルダという機能だった。
プレースホルダとはパラメータを後で記述できるようにすることによって、SQLの構文を決定した後にバインドできるのでパラメータがリテラルの外にはみ出す現象が起こらなくなりSQLインジェクションが起こらなくなる機能だ。

 
 

普段SQL文を書いていないことが露呈してしまいました...基礎技術を勉強し直そうと思います。
ご指摘ありがとうこざいます!
 

?を使うSQL文は色々なところで見たことはありましたがプレースホルダという名前があったのは知りませんでした。
ご指摘のおかげでgoogle先生に聞くことができました。ありがとうございます!


方法

検索フォームに ‘); DROP “posts”;— '); DROP TABLE “posts”;-- と入力する
SQLインジェクションが通る状態で複文はどうなるのか試してみた。

結果

SELECT "users"."id" FROM "users" WHERE (username LIKE '%‘); DROP “posts”;--%')
SELECT "users"."id" FROM "users" WHERE (username LIKE '%'); DROP TABLE “posts”;--%') というクエリが発行されているもののpostsテーブルは削除されていなかった。
なので複文はサポートされてないみたい。(今回はSQLite3での実験だったので他のDBでどうなるかは試していません)

まとめ

  • やはり自分の書いたコードに穴があった。
  • XSSSQLインジェクションチートシートの存在を知ったことが一番の収穫だった。
  • マサカリを投げて間違いを指摘してくれる人がいる。アウトプットの重要性を改めて実感した。

 

参考にさせていただきました

SQL Injection Cheat Sheet
Railsで検索をSQLで簡単に実装する方法 - Qiita
Railsのセキュリティ対策で調べた事 - Qiita
XSS Filter Evasion Cheat Sheet - OWASP
html_safe、raw、「<%==」の比較 - Qiita
https://www.ipa.go.jp/files/000017320.pdf
rails - クエリの基本 - そういうことだったんですね

Railsでセキュリティのことを考えずに作ったwebアプリは脆弱性があるのか調べてみた(webアプリ作成編)

こんにちは。僕はこのたびセキュリティキャンプ九州2016に行ってきました。
一言感想を言わせていただくと大変面白かったです。
ただ一つ不安になったことがあります。それはwebアプリの脆弱性です。 キャンプ中にwebアプリの脆弱性を見つけてみようという講座があり、脆弱性があるwebアプリを公開してみんなで脆弱性を探すというものだったのですが、30分もたたないうちに実装されてないはずの画像アップロード機能が追加されたりページを開いた瞬間音声が流れ出す迷惑サイトに変化していたりと蜂の巣状態になっていました。

そこで今回は普段使っているRuby on Railsで作ったwebアプリに脆弱性が存在するのかを確かめてみようと思います。

仕様

セキュリティキャンプ九州で使用した脆弱SNSの機能は次のようなものでした。

  • ログイン機能(登録・編集)
  • ログインすると掲示板への投稿・削除ができる
  • 投稿内容の一覧
  • 投稿とユーザの検索機能

DB

  • 投稿テーブル(内容/投稿者/日時)
  • ユーザテーブル(ユーザ名/パスワード/URL)

これと同じような機能のwebアプリをRailsでできるだけコードを書かずに作ってみたいと思います。
Railsではログイン機能はコマンドだけでは生成できないので超有名なユーザー管理のgemであるDeviseを使いました。

環境

Rails 4.2.4
Devise 4.1.1

ログイン機能

まずはrailsアプリを生成。 以下のコマンドを実行します。

% rails new testApp
      create
      create  README.rdoc
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/assets/javascripts/application.js
      create  app/assets/stylesheets/application.css
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
  — 略 —
      create  vendor/assets/stylesheets/.keep
         run  bundle install
Fetching gem metadata from https://rubygems.org/
Fetching version metadata from https://rubygems.org/
Fetching dependency metadata from https://rubygems.org/
Resolving dependencies......
Using rake 11.2.2
Using i18n 0.7.0
Using json 1.8.3
— 略 —

Gemfileに以下を追記。

# Gemfile
gem ‘devise’ 

bundle installを実行。
% bundle install

rails generateでdeviseをインストールします。
これでユーザー管理を行うための準備が完了します。

% bundle exec rails generate devise:install
Running via Spring preloader in process 4640
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

言われた通りに設定していきます。
development.rbに追記します。

# config/enviroments/development.rb  
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
    :address => 'smtp.gmail.com',
    :port => 587,
    :authentication => :plain,
    :user_name => 'メールアドレス',
    :password => 'パスワード'
}

root用のcontrollerとviewをコマンドで生成します。

% bundle exec rails generate controller home index
Running via Spring preloader in process 7935
      create  app/controllers/home_controller.rb
       route  get 'home/index'
      invoke  erb
      create    app/views/home
      create    app/views/home/index.html.erb
      invoke  test_unit
      create    test/controllers/home_controller_test.rb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/home.coffee
      invoke    scss
      create      app/assets/stylesheets/home.scss

routes.rbに追記してroot_urlを設定します。

# config/routes.rb
root to: "home#index"

home/index.html.erbにログインと登録用のURLを追加します。

<h1>Home#index</h1>
<% if user_signed_in? %>
  Logged in as <strong><%= current_user.email %></strong>.
  <%= link_to "Settings", edit_user_registration_path, :class => "navbar-link" %> |
  <%= link_to "Logout", destroy_user_session_path, method: :delete, :class => "navbar-link" %>
<% else %>
  <%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
  <%= link_to "Login", new_user_session_path, :class => 'navbar-link' %>
<% end %>
<p>Find me in app/views/home/index.html.erb</p>

ログイン情報を出力させるためにlayouts/application.html.erbに追加します。

<!DOCTYPE html>
<html>
<head>
  <title>TestApp</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>
<% if notice %>
  <p class="alert alert-success"><%= notice %></p>
<% end %>
<% if alert %>
  <p class="alert alert-danger"><%= alert %></p>
<% end %>
<%= yield %>

</body>
</html>

次にユーザー用のmodelとmigrationファイルを生成します。

% bundle exec rails generate devise User
Running via Spring preloader in process 4790
      invoke  active_record
      create    db/migrate/(タイムスタンプ)_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

今回はtrackableとvalidatableは使わないので user.rbの一部をコメントアウトします。

# app/models/user.rb
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registrable,
         :recoverable, :rememberable
        # :trackable,
        # :validatable
end

その修正に合わせて (タイムスタンプ)__devise_create_users.rbの一部もコメントアウトします。

# db/migrate/(タイムスタンプ)__devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # 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

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    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
end

DBを生成します。以下のコマンドを実行してください。

% bundle exec rake db:migrate
== 20160920061425 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0012s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0007s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0008s
== 20160920061425 DeviseCreateUsers: migrated (0.0029s) =======================

rails s でサーバを起動させ、http://localhost:3000にアクセスするとこうなります。 f:id:euglena1215:20160921160404p:plain

Sign upから登録をすませると f:id:euglena1215:20160921160515p:plain

これでdeviseのデフォルトのログイン機能は完了ですが、現在ではユーザ情報がメールアドレスとパスワードしか存在しません。 なのでユーザ情報にユーザ名を追加し、ユーザ名とパスワードでログインできるようにします。

以下のコマンドを実行します。

% rails generate migration add_username_to_users username:string
Running via Spring preloader in process 9875
      invoke  active_record
      create    db/migrate/(タイムスタンプ)_add_username_to_users.rb

usernameはログインで使われるためuniqueを与えます。 (タイムスタンプ)_add_username_to_users.rbに追記します。

#db/migrate/(タイムスタンプ)_add_username_to_users.rb
class AddUsernameToUsers < ActiveRecord::Migration
  def change
    add_column :users, :username, :string
    add_index :users, :username, unique: true
  end
end

以下のコマンドを実行します。

% bundle exec rake db:migrate
== 20160920080558 AddUsernameToUsers: migrating ===============================
-- add_column(:users, :username, :string)
   -> 0.0018s
-- add_index(:users, :username, {:unique=>true})
   -> 0.0025s
== 20160920080558 AddUsernameToUsers: migrated (0.0045s) ======================

user.rbにvalidationを追加します。

validates :username, presence: true, uniqueness: true

ログインで使うデータを変更したため、viewをカスタマイズします。

以下のコマンドを実行します。

% rails g devise:views
Running via Spring preloader in process 11412
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/devise/shared
      create    app/views/devise/shared/_links.html.erb
      invoke  form_for
      create    app/views/devise/confirmations
      create    app/views/devise/confirmations/new.html.erb
      create    app/views/devise/passwords
      create    app/views/devise/passwords/edit.html.erb
      create    app/views/devise/passwords/new.html.erb
      create    app/views/devise/registrations
      create    app/views/devise/registrations/edit.html.erb
      create    app/views/devise/registrations/new.html.erb
      create    app/views/devise/sessions
      create    app/views/devise/sessions/new.html.erb
      create    app/views/devise/unlocks
      create    app/views/devise/unlocks/new.html.erb
      invoke  erb
      create    app/views/devise/mailer
      create    app/views/devise/mailer/confirmation_instructions.html.erb
      create    app/views/devise/mailer/password_change.html.erb
      create    app/views/devise/mailer/reset_password_instructions.html.erb
      create    app/views/devise/mailer/unlock_instructions.html.erb

以下のviewの current_user.emailcurrent_user.username に変更します。
app/views/home/index.html.erb

以下のviewの :email:username に変更し、 email_fieldtext_field に変更します。
app/views/devise/sessions/new.html.erb

以下のviewにusername用のフォームを追加します。
app/views/devise/registrations/new.html.erb
app/views/devise/registrations/edit.html.erb

先ほど登録したuserはusernameにデータが入っていないので一度DBをリセットします。
以下のコマンドを実行します。

% bundle exec rake db:migrate:reset
== 20160920061425 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0013s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0007s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0007s
== 20160920061425 DeviseCreateUsers: migrated (0.0029s) =======================

== 20160920080558 AddUsernameToUsers: migrating ===============================
-- add_column(:users, :username, :string)
   -> 0.0006s
-- add_index(:users, :username, {:unique=>true})
   -> 0.0011s
== 20160920080558 AddUsernameToUsers: migrated (0.0018s) ======================

rails s でサーバを起動し http://localhost:3000/users/sign_upにアクセスすると f:id:euglena1215:20160921160700p:plain

usernameも登録できるようになっていて f:id:euglena1215:20160921160719p:plain

usernameとpasswordでログインできるようになっています。

次にURLカラムを追加します。 以下のコマンドを実行します。

% rails generate migration add_url_to_users url:string
Running via Spring preloader in process 12882
      invoke  active_record
      create    db/migrate/20160920090632_add_url_to_users.rb

先ほどと同様に以下のviewにurl用のフォームを追加します。
app/views/devise/registrations/new.html.erb
app/views/devise/registrations/edit.html.erb

先ほど登録したuserはurlを持っていないので一度DBをリセットします。
以下のコマンドを実行します。

% bundle exec rake db:migrate:reset
== 20160920061425 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0012s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0006s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0007s
== 20160920061425 DeviseCreateUsers: migrated (0.0028s) =======================

== 20160920080558 AddUsernameToUsers: migrating ===============================
-- add_column(:users, :username, :string)
   -> 0.0006s
-- add_index(:users, :username, {:unique=>true})
   -> 0.0010s
== 20160920080558 AddUsernameToUsers: migrated (0.0017s) ======================

== 20160920090632 AddUrlToUsers: migrating ====================================
-- add_column(:users, :url, :string)
   -> 0.0005s
== 20160920090632 AddUrlToUsers: migrated (0.0006s) ===========================

これでログイン機能はOKです。

投稿機能

以下のコマンドを実行します。

% rails g scaffold post body:text user:references
Running via Spring preloader in process 13853
      invoke  active_record
      create    db/migrate/20160920092635_create_posts.rb
      create    app/models/post.rb
      invoke    test_unit
      create      test/models/post_test.rb
      create      test/fixtures/posts.yml
      invoke  resource_route
       route    resources :posts
      invoke  scaffold_controller
      create    app/controllers/posts_controller.rb
      invoke    erb
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
      invoke    test_unit
      create      test/controllers/posts_controller_test.rb
      invoke    helper
      create      app/helpers/posts_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/posts/index.json.jbuilder
      create      app/views/posts/show.json.jbuilder
      create      app/views/posts/_post.json.jbuilder
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/posts.coffee
      invoke    scss
      create      app/assets/stylesheets/posts.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss

ユーザと投稿は1対多の関係なのでrelationをuser.rbに追記します。
また、ユーザが削除されたときにそのユーザの投稿も削除してほしいのでdependent属性も設定します。

# app/models/user.rb
has_many :posts, dependent: :destroy

以下のコマンドを実行します。

% bundle exec rake db:migrate
== 20160920092635 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0017s
== 20160920092635 CreatePosts: migrated (0.0017s) =============================

投稿と投稿者が結びつくようにフォームを修正します。

# app/views/posts/_form.html.erb
<div class="field">
  <%= f.label :body %><br>
  <%= f.text_area :body %>
  <%= f.hidden_field :user_id, value: current_user.id %>
</div>

まだ色々な微調整は済んでいませんが、基本的な投稿機能は完成です。 (書くのが面倒くさくなりました。誠に申し訳ございません。一番下にソースのリンクを貼っておくので参考にしてください)

検索機能

次に検索機能を実装します。 今後も使っていくようなアプリであれば検索機能用のgemであるransackを使うのですが、今回は簡単な検索のみなのでgemを使わずに実装しようと思います。

まずはscopeを実装します。post.rbとuser.rbに追記してください。

# app/models/post.rb
scope :by_body_like, ->(body){
  where("body LIKE '%"+body+"%'")
}

scope :by_users_id, ->(users_id){
  where(user_id: users_id)
}
# app/models/user.rb
scope :by_username_like, ->(username){
  where("username LIKE '%"+username+"%'")
}

これで Post.by_body_like(‘hoge’) で投稿内容に’home'が含まれる投稿を取得することができます。
また、 Post.by_users_id(User.by_username_like(‘foo’).pluck[:id]) でユーザー名に’foo’が含まれるユーザーの投稿を取得することができます。
注意!! この記述には脆弱性が存在します。詳しくは脆弱性検証編を書いてあります。

次は検索機能で用いるラジオボタン用の定数を設定します。 post.rbに追記します。

# app/models/post.rb
POST_SEARCH = 1
USER_SEARCH = 2

この定数は Post::POST_SEARCH と記述すると使えます。

次にcontrollerを記述します。
今回の検索機能はsearch_typeで検索する対象(postのbody,userのusername)を決定し、searchが検索ワードという実装にしました。
posts_controller.rbのindexメソッドを次のように変更します。

# app/controllers/posts_controller.rb
def index
  if params[:search_type] == Post::POST_SEARCH.to_s
    @posts = Post.by_body_like(params[:search])
  elsif params[:search_type] == Post::USER_SEARCH.to_s
    users_id = User.by_username_like(params[:search]).pluck(:id)
    @posts = Post.by_users_id(users_id)
  else
    @posts = Post.all
  end
end

Post::POST_SEARCH.to_sとなっているのはGETメソッドから得られるパラメータは数値も文字列に変換されているためです。

次にviewを記述します。
posts/index.html.erbに追記します。

# app/views/posts/index.html.erb
<%= form_tag({controller: '/posts',action: 'index'}, method: 'get', class: 'search_form', style: 'padding: 20px;') do %>
  <div class="field">
    <%= radio_button_tag :search_type, Post::POST_SEARCH %>
    <%= label_tag :post %>
    <%= radio_button_tag :search_type, Post::USER_SEARCH %>
    <%= label_tag :user %>
  </div>
  <div class="field">
    <%= text_field_tag :search,'' %>
  </div>
  <div class="actions">
    <%= submit_tag '検索' %>
  </div>
<% end %>

これで検索機能は完成です。

ここから

  • 新規投稿機能をトップページに持ってくる
  • bootstrapをCDNで読み込ませる
  • UIの調整
  • 使ってないメソッド、ルーティング、ビューを削除
  • タイムゾーンを東京に変更

などなどを書き換えると脆弱かもしれないSNSの完成です。 f:id:euglena1215:20160921162147p:plain

次は脆弱性検証編です。 euglena1215.hatenablog.jp

ソースはこちら GitHub - euglena1215/testApp

【大学編入】専門科目の参考書と対策

参考書

プログラミング

C言語によるアルゴリズムとデータ構造

新・明解C言語によるアルゴリズムとデータ構造

新・明解C言語によるアルゴリズムとデータ構造

色々な編入体験記に載っているのアルゴリズムの本です。 基礎固めに役立ちました。
1周

プログラミングコンテストチャレンジブック

通称アリ本です。「C言語によるアルゴリズムとデータ構造」にはグラフ理論や有名なアルゴリズム(エラトステネスの篩、ダイクストラなど)が載ってなかったのでそれらを実装方法を主眼において読みました。ソースはC++ですがCが分かれば読めると思います。

アルゴリズムとデータ構造(青)

アルゴリズムとデータ構造<改訂 C言語版> (電気工学入門シリーズ)

アルゴリズムとデータ構造<改訂 C言語版> (電気工学入門シリーズ)

C言語によるアルゴリズムとデータ構造」にはグラフ理論や有名なアルゴリズム(エラトステネスの篩、ダイクストラなど)が載ってなかったのでそれらを理論的なところを主眼において読みました。この本とアリ本を行ったり来たりしながら勉強すると捗ると思います。 先生に「C言語によるアルゴリズムとデータ構造のワンランク上でダイクストラとか載ってる本貸してください」と言ったらこの本を貸してくれました。

アルゴリズム図鑑

アルゴリズム図鑑

アルゴリズム図鑑

  • Moriteru Ishida
  • 教育
  • 無料
基本的な探索、ソートの名前を聞いたらすぐに挙動をイメージできるように暇なときはこのアプリを使って確認してました。アニメーションを使って分かりやすく説明してくれてるのでとてもイメージしやすかったです。 300円課金すると全てのアルゴリズムが解放されるのですが課金する価値は十分にありました。

論理回路

論理回路入門

論理回路入門 第2版

論理回路入門 第2版

ざーっと一通り読んでから練習問題を解きました。 意外と時間がかかるので注意してください

情報理論

情報理論

情報理論 (電気・電子系教科書シリーズ)

情報理論 (電気・電子系教科書シリーズ)

この本は授業で使ってたのでそのまま使いました。

対策

対策を始める前の僕は「クイックソート、なんか早そう」「グラフ理論なにそれおいしいの?」「計算量ってなんですか」「篩が読めねえ」というような状況で初めて筑波の過去問を解いたときは解き終わるのに2時間半かかり(筑波は数学と専門合わせて2時間)もう死んだと思ってました。
どうせ他の人も同じようなもんだろと思い編入体験記を漁ると「筑波の専門は簡単」「競プロやってたらいける」「直前の1週間に過去問解きまくったらいけた」という記事ばかりで絶望しかありませんでした。
なので他の人より多めに勉強しました。
論理回路情報理論は勉強すれば点が取れると思います。

 

対策の方針はこんな感じでした。
プログラミング
参考書をばーっと読む+写経する
過去問解く
解けない&時間がかかり過ぎるところを中心に参考書を読む
もう一度過去問を解く
を繰り返す
暇なときはアルゴリズム図鑑で復習する

論理回路
論理回路をばーっと目を通す
演習問題を解く
過去問を解く
もう一度過去問を解く
を繰り返す

情報理論
情報理論にバーっと目を通す
過去問を解く
もう一度過去問を解く
を繰り返す

 

僕の勉強のおおまかな流れは
プログラミング
3月下旬~4月上旬
アルゴリズムとデータ構造 読む 1周
4月上旬~試験日
過去問を繰り返し解く、アリ本、アルゴリズムを必要に応じて読む

論理回路
4月中旬~5月中旬
毎週金曜 3時間前後
5月中旬~試験日
過去問を解く

情報理論
6月~試験日
気が向いたときに過去問を解く
分からなかったら情報理論を読む

下の記録を見てもらえれば詳細の勉強記録が載っています。
http://studyplus.jp/users/teppest

 
編入体験記をまとめました。
euglena1215.hatenablog.jp

rake db:migrateとrake db:schema:loadの違い

rake db:migraterake db:schema:load はどちらもテーブルを作成、変更、削除するときに使うコマンドだけど違いがよく分かっていなかったのでメモメモ。

rake db:migrate

  1. migrateファイル群を元にschema.rbを作成
  2. schema.rbを元にSQLクエリを発行する

rake db:schema:load

  1. schema.rbを元にSQLクエリを発行する

 

 

要するにrake db:schema:load はmigrateファイルの変更は考慮しないよってことか。

ローカルでは rake db:migrete , CIツール上では rake db:schema:load と使い分けるのが一般的で、そうすることによってmigrateし忘れてpushしてもCIツール上のschema.rbのバージョンが同じになるようにしてるみたい。 賢いなあ。

【大学編入】物理の参考書と対策

参考書

力学

基礎 物理学演習Ⅰ

基礎物理学演習 (1) (ライブラリ工学基礎物理学 (別巻=1))

基礎物理学演習 (1) (ライブラリ工学基礎物理学 (別巻=1))

力学の勉強はこれから始めましたが難しかったので10ページほどで断念しました。
結局この参考書に戻ってくることはありませんでした。

物理のエッセンス 力学・波動

物理のエッセンス 力学・波動 (河合塾シリーズ)

物理のエッセンス 力学・波動 (河合塾シリーズ)

基礎物理学演習で培った苦手意識を克服するために基礎から勉強を始めました。物理対策の導入にはいいと思います。
1周

良問の風

良問の風物理頻出・標準入試問題集 (河合塾シリーズ)

良問の風物理頻出・標準入試問題集 (河合塾シリーズ)

物理のエッセンスより難易度の高い問題集を解こうと思って解き始めたのですが、物理のエッセンスと難易度は変わりませんでした。
物理のエッセンスをスラスラ解けるようになっているのであればワンランク上の名門の森をやった方がいいと思います。僕は時間がなくてできませんでした。
1周

基礎 物理学演習

基礎 物理学演習

基礎 物理学演習

横国の範囲が高校物理と剛体だったのでこの本で剛体をカバーしました。
剛体の例題のみ 1周

電磁気

基礎 物理学演習

基礎 物理学演習

基礎 物理学演習

サイエンス社電磁気学演習よりこっちの方が薄かったのでこちらを選びました。
難しくて答えを写すことが多く、やった意味があったのかどうかは不明です。
1周


対策

僕は農工大横国の物理で対応できる程度の物理対策しかしていないので旧帝大東工大狙いの人は参考にしないでください。

力学と電磁気は問題集を解いて基礎作りをしてから過去問を何周もしました。物理の対策は過去問を何度も解くのが効率よく点数を取る方法な気がします。
解けない過去問は先生や友達に聞いて解答を作りました。
分からない問題を悩んでる時間がもったいないと思ったので嫌われない程度に他人の時間をガンガン使うのが吉だと思います。

対策の方針はこんな感じでした。
力学
基礎物理学演習(黄色) 10ページほどで断念

物理のエッセンス 1周

良問の風 1周

過去問 たくさん

電磁気
基礎物理学演習(青) 1周

過去問 たくさん

僕の勉強のおおまかな流れはこんな感じでした。
力学
春休み始め~春休み中盤
基礎物理学演習(黄色) 3日に1度 30分
春休み中盤~春休み終わり
物理のエッセンス 1日 1時間前後
4月~5月上旬
良問の風 1日 1時間前後
5月上旬~試験まで
過去問 1日1年分、基礎物理学演習 剛体の範囲を適当に

電磁気
4月~5月上旬
基礎物理学演習(青) 1日2例題
5月上旬~試験まで
過去問 1日1年分

下の記録を見てもらえれば詳細の勉強記録が載っています。
http://studyplus.jp/users/teppest

 
編入体験記をまとめました。
euglena1215.hatenablog.jp