railsのbelongs_toとhas_manyとreferencesの使い方について整理する
ややこしいので、一気に整理する。
空のrailsプロジェクトを立ち上げて、
$ be rails g model user name:text
※ alias be='bundle exec'
userテーブルができました。
$ be rails g model tweet content:text references:users
tweetテーブルができました。
こいつらモデルのクラスを確認してみると、
app/models/user.rb
class User < ApplicationRecord end
app/models/tweet.rb
class Tweet < ApplicationRecord end
dbマイグレートする
$ be rake db:migrate == 20180717181025 CreateTweets: migrating ===================================== -- create_table(:tweets) rake aborted! StandardError: An error has occurred, this and all later migrations canceled: undefined method `user' for #<ActiveRecord::ConnectionAdapters::SQLite3::TableDefinition:0x00007ff17cfc1488> . ,
と、エラーになる。
これは、もしかして順番がよろしくなかったか?
もう一度やり直す。
$ be rails g model user name:text $ be rake db:migrate $ be rails g model tweet content:text references:user $ be rake db:migrate == 20180717181557 CreateTweets: migrating ===================================== -- create_table(:tweets) rake aborted! StandardError: An error has occurred, this and all later migrations canceled: undefined method `user' for #<ActiveRecord::ConnectionAdapters::SQLite3::TableDefinition:0x00007fc20b59a978> . . .
順番なんとか関係なかったです、すみません。
たぶんuserを複数形にしたら行ける気がする。
そのために、一度2つ目のmigrationファイルはなかったことにする。
$ be rails destroy model tweet $ be rails g model tweet content:text references:users $ be rake db:migrate . . undefined method `users' for #<ActiveRecord::ConnectionAdapters::SQLite3::TableDefinition:0x00007f8ab5104ea0>
うーむ。先にreferencesを使わない方法を実装して確認する。
もう一度もとに戻します。
$ be rails destroy model tweet
シンプルなやつ
$ be rails g model tweet content:text user_id:integer $ be rake db:migrate
成功。
しかしこれでは、ただ単にuser_idというたまたまuserテーブルと関係ありそうな名前のカラムがあるだけで、実際には無関係です。
2つのファイルを次のように変更
app/models/user.rb
class User < ApplicationRecord has_many :tweets end
app/models/tweet.rb
class Tweet < ApplicationRecord belongs_to :user end
そして、rails consoleにて試してみる。
まずは一通り。
be rails c -s Loading development environment in sandbox (Rails 5.2.0) Any modifications you make will be rolled back on exit irb(main):001:0> u = User.create(name:"hoge") (0.1ms) SAVEPOINT active_record_1 User Create (0.6ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "hoge"], ["created_at", "2018-07-17 18:34:37.448049"], ["updated_at", "2018-07-17 18:34:37.448049"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<User id: 1, name: "hoge", created_at: "2018-07-17 18:34:37", updated_at: "2018-07-17 18:34:37"> irb(main):002:0> irb(main):003:0> irb(main):004:0> irb(main):005:0> irb(main):006:0> t = Tweet.create(content:"aaaaaaaa", user_id:1) (0.1ms) SAVEPOINT active_record_1 User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Tweet Create (0.2ms) INSERT INTO "tweets" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "aaaaaaaa"], ["user_id", 1], ["created_at", "2018-07-17 18:35:22.904090"], ["updated_at", "2018-07-17 18:35:22.904090"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<Tweet id: 1, content: "aaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:22", updated_at: "2018-07-17 18:35:22"> irb(main):007:0> t2 = Tweet.create(content:"bbbbbaaaaaaaa", user_id:1) (0.1ms) SAVEPOINT active_record_1 User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Tweet Create (0.2ms) INSERT INTO "tweets" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "bbbbbaaaaaaaa"], ["user_id", 1], ["created_at", "2018-07-17 18:35:29.800640"], ["updated_at", "2018-07-17 18:35:29.800640"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<Tweet id: 2, content: "bbbbbaaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:29", updated_at: "2018-07-17 18:35:29"> irb(main):008:0> irb(main):009:0> irb(main):010:0> irb(main):011:0> irb(main):012:0> irb(main):013:0> irb(main):014:0> u.tweets Tweet Load (0.2ms) SELECT "tweets".* FROM "tweets" WHERE "tweets"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 11]] => #<ActiveRecord::Associations::CollectionProxy [#<Tweet id: 1, content: "aaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:22", updated_at: "2018-07-17 18:35:22">, #<Tweet id: 2, content: "bbbbbaaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:29", updated_at: "2018-07-17 18:35:29">]> irb(main):015:0> irb(main):016:0> irb(main):017:0> irb(main):018:0> irb(main):019:0> t.user => #<User id: 1, name: "hoge", created_at: "2018-07-17 18:34:37", updated_at: "2018-07-17 18:34:37">
sqlをちょっと読んでみる。 まずは一つ目。Userの作成。
u = User.create(name:"hoge") (0.1ms) SAVEPOINT active_record_1 User Create (0.6ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "hoge"], ["created_at", "2018-07-17 18:34:37.448049"], ["updated_at", "2018-07-17 18:34:37.448049"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<User id: 1, name: "hoge", created_at: "2018-07-17 18:34:37", updated_at: "2018-07-17 18:34:37">
特に難しいことはしていない。ここは至ってシンプル。
ただ、(?, ?, ?)とかの部分はなんかエスケープしてるんだろうくらいの雰囲気で流している。
続いてTweetの作成。
t = Tweet.create(content:"aaaaaaaa", user_id:1) (0.1ms) SAVEPOINT active_record_1 User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Tweet Create (0.2ms) INSERT INTO "tweets" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "aaaaaaaa"], ["user_id", 1], ["created_at", "2018-07-17 18:35:22.904090"], ["updated_at", "2018-07-17 18:35:22.904090"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<Tweet id: 1, content: "aaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:22", updated_at: "2018-07-17 18:35:22">
なるほど、一度Userの情報を探している。
ちなみに、createの際にuser_idを指定しなかったり、usersテーブルのidに存在しない値を指定すると、失敗し、rollbackする。
userに紐づくtweetを取得する
u.tweets Tweet Load (0.2ms) SELECT "tweets".* FROM "tweets" WHERE "tweets"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 11]] => #<ActiveRecord::Associations::CollectionProxy [#<Tweet id: 1, content: "aaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:22", updated_at: "2018-07-17 18:35:22">, #<Tweet id: 2, content: "bbbbbaaaaaaaa", user_id: 1, created_at: "2018-07-17 18:35:29", updated_at: "2018-07-17 18:35:29">]>
なるほど、かってにuserテーブルのidをtweetテーブルのuser_idに変換してwhereの条件をかけているわけか。
最後に、Tweetに紐付いたuserの情報
t.user => #<User id: 1, name: "hoge", created_at: "2018-07-17 18:34:37", updated_at: "2018-07-17 18:34:37">
はっ!? SQLは発行されないのか!! これはー多分最初にtを作成したときにuser_idを指定していて、そのときにuserの情報がloadされていたので、それを利用しているぽい。
なるほどね、SQLの中身がわかってちゃんと落ち着いて読めばそんなに対してことやってないってことがわかった。
ただし、userテーブルのidをtweetテーブルのuser_idに変換するとか、名前で制約をつけていることが多くて、そこ離れるまでは大変そうだと思ったよ。
referenceを理解する
これと同じことをreferencesを使ってやってみる。
ちょっと改めて調べたところ、さっき自分がやっていたことはとんでもないウンコマンなことだった。
改めて空のrailsプロジェクトから
$ be rails g model user name:text $ be rails g model tweet content:text user:references $ be rake db:migrate
userという名前の型がreferencesというわけだ。
先程までのエラーは、referencesというカラムをuserという型で定義しようとしていたために発生したエラーだったのだった。。。ゴミすぎる。笑
モデルのクラスのファイルを見てみる。
app/models/user.rb
class User < ApplicationRecord end
app/models/tweet.rb
class Tweet < ApplicationRecord belongs_to :user end
おっと、このままの状態だと、Userクラスに何も書いてないが、果たしてこれで動くのか?
rails consoleで確認。
be rails c -s Loading development environment in sandbox (Rails 5.2.0) Any modifications you make will be rolled back on exit irb(main):001:0> u = User.create(name: "hoge") (0.1ms) SAVEPOINT active_record_1 User Create (0.6ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "hoge"], ["created_at", "2018-07-18 14:01:54.105305"], ["updated_at", "2018-07-18 14:01:54.105305"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<User id: 1, name: "hoge", created_at: "2018-07-18 14:01:54", updated_at: "2018-07-18 14:01:54"> irb(main):002:0> irb(main):003:0> irb(main):004:0> irb(main):005:0> irb(main):006:0> t = Tweet.create(content: "aaaaaaa", user_id:1) (0.1ms) SAVEPOINT active_record_1 User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Tweet Create (0.3ms) INSERT INTO "tweets" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "aaaaaaa"], ["user_id", 1], ["created_at", "2018-07-18 14:02:19.665391"], ["updated_at", "2018-07-18 14:02:19.665391"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<Tweet id: 1, content: "aaaaaaa", user_id: 1, created_at: "2018-07-18 14:02:19", updated_at: "2018-07-18 14:02:19"> irb(main):007:0> irb(main):008:0> irb(main):009:0> irb(main):010:0> irb(main):011:0> u => #<User id: 1, name: "hoge", created_at: "2018-07-18 14:01:54", updated_at: "2018-07-18 14:01:54"> irb(main):012:0> u.tweets Traceback (most recent call last): 1: from (irb):12 NoMethodError (undefined method `tweets' for #<User:0x00007f9dc8987f48>) irb(main):013:0> irb(main):014:0> irb(main):015:0> irb(main):016:0> irb(main):017:0> irb(main):018:0> t.user => #<User id: 1, name: "hoge", created_at: "2018-07-18 14:01:54", updated_at: "2018-07-18 14:01:54"> irb(main):019:0>
userからtweetを取得するのができない。
やはりuser has_many tweetと定義していないからだ。
しかし、tweet belongs_to userなので、tweetからuserを取得することはできる。
なので、相互からアクセスしたいときには、
app/models/user.rb
class User < ApplicationRecord has_many :tweets end
と、has_manyを追加する必要がある。
ところで、型をreferencesとして定義するメリットは何なんだろう?
確かに、belongs_toは自動で書いてくれたけど、結局has_manyを自分で書かないといけないんだったら、そんなに旨味はないように感じるのだが。。。
外部キーをreferences型カラムで保存する
によると、references型はbelongs_toと同じ意味だと。
references型でテーブル定義をすると、hoge_idというように"_id"をつけなくてもいいらしい。
しかし、これがメリットなのか?
【Rails入門】has_many、belongs_toの使い方まとめ | 侍エンジニア塾ブログ | プログラミング入門者向け学習情報サイト
また、referencesを使った場合はapp/model/castle.rb にbelongs_to :ownerが自動で追加されます。 ですので、使えるなら、いちいち手動で設定するよりもこちらのコマンドを使うよにしてください。
この記事のニュアンスだと、別にreferences使わないとだめってことはないみたい。
そうか、別にreferencesじゃなくてもいいのか、ただreferences使ったほうがちょっと便利でラクできるよ!ってことらしい。
そういう理解にしておいて先に進もう。
と、最後にdb/schema.rb
だけは確認しておきたい。
referencesを使ってmigrationファイルを作成した場合。
ActiveRecord::Schema.define(version: 2018_07_17_194545) do create_table "tweets", force: :cascade do |t| t.text "content" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_tweets_on_user_id" end create_table "users", force: :cascade do |t| t.text "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
なるほど、tweetテーブル側でuser_idにindex的なものがあるなぁ。
しまった、sqlのindexについての知識が乏しい。。。
なんか早くなるっぽいくらいの認識しかない。辛み。
一旦保留にして、referencesじゃなくて、それぞれ別のものとしてuserテーブルとtweetテーブルを作ったものを見てみる。
be rails g model user name:text
be rails g model tweet content:text user_id:integer
be rake db:migrate
db/schema.rb
ActiveRecord::Schema.define(version: 2018_07_18_142813) do create_table "tweets", force: :cascade do |t| t.text "content" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.text "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
うーむ、tweetsテーブルのuser_idはusersテーブルとは無関係のように見えるな。
これは適当だがreferencesを使ったほうがindex的なものを使うからテーブル感のリレーションを使いたいときには高速。的なことがありそうな気がしてきた。がわからない。
そんなゴリゴリにsqlチューニングする必要ある勢じゃないから、いいや、気にしない。タイムカプセルに入れておこう。
と、やはり気になってteratailにアカウント作って質問の文章を書いている最中にダメ押しでもう少し調べてみたら、多分理解した。
Ruby on Rails - railsのindexとforeign_keyについておしえてください。(63406)|teratail
やっぱり普通にindexを使っているんですね。
そしてindexも概念は理解しました。
sqlのindexの説明で「複製」とかっていう単語を使っていたので、腑に落ちていなかったが、どうやらこういうことらしい。
indexについて理解があいまいなのですが、 --------+--------+---------+
| id | name | shoku |
|1 | taro | ramen |
| 2 | ken | somen |
こんなデータがあったとして、nameフィールドにindexをつけたとすると、よみだすときこのデータ全体を読み込むのではなく、nameフィールドだけを絞って読み込むということですか? だとしたら find_by があるのでindexが不要だと思ったのですが。。。
という質問に対して
たとえば、ユーザーのデータが数百万件を超えるような膨大な数になったとしましょう。 その中から、「メールアドレスがhoge@example.comのデータを探す」となれば、インデックスがない場合だと「全部のデータを当たって、一致するメールアドレスを探す」という処理が必要になります。一方、インデックスでは「B木」のような完全に同一のデータ、あるいはデータ範囲を検索しやすいような特殊な構造でデータを入れてあるので、メールアドレスが一致するデータを、全探索より遥かに高速に引き出すことができます。
Ruby on Rails - railsのindexとforeign_keyについておしえてください。(63406)|teratail
なるほど、普通に複製するだけじゃなくて、B木とかの検索しやすいデータ構造にしておくのか。
いやーCS力足りないなぁ。。。
ということは、結局テーブル同士のリレーションは結構な数の呼び出しが起こりそうな気がしているので、indexを貼ってくれているrefernces型を使うのがbetterという結論でよろしいですかね。
twitter分析アプリ②
バッチ処理をするにはrakeタスクってのを使うみたいだ。
rakeタスクってのは、いままでおまじない的に使っていた
$ be rake db:migrate
※ alias be='bundle exec'
とかで呼び出されるタスクのことらしい。
作り方は簡単。
$ be rails g task task_sample
これで生成されたファイルlib/tasks/task_sample.rake
namespace :task_sample do end
を、次のように書き換えてみる。
namespace :task_sample do desc "実行処理の説明" task :sample do puts "Hello World" end end
これで、呼び出すときはコンソールから
$ be rake task_sample:sample Hello World
→OK。Hello Worldが表示されました。
コロンの前が、rakeファイルの名前で、
コロンの後が、taskの名前ということか!
今までの
$ be rake db:migrate
も、dbというrakeファイルの、migrateというtaskを実行していたに過ぎなかったのか〜!
これは学び。
ちなみにrakeタスク一覧はこれで見られると。
be rake -vT rake about # List versions of all Rails frameworks and the environment rake active_storage:install # Copy over the migration needed to the application rake active_storage:install:migrations # Copy migrations from active_storage to application rake app:template # Applies the template supplied by LOCATION=(/path/to/template) or URL rake app:update # Update configs and some other initially generated files (or use just update:configs ... rake assets:clean[keep] # Remove old compiled assets rake assets:clobber # Remove compiled assets rake assets:environment # Load asset compile environment rake assets:precompile # Compile all the assets named in config.assets.precompile rake cache_digests:dependencies # Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_commen... rake cache_digests:nested_dependencies # Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html) rake db:create # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_... rake db:drop # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_EN... rake db:environment:set # Set the environment value for the database rake db:fixtures:load # Loads fixtures into the current environment's database rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog) rake db:migrate:status # Display status of migrations rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n) rake db:schema:cache:clear # Clears a db/schema_cache.yml file rake db:schema:cache:dump # Creates a db/schema_cache.yml file rake db:schema:dump # Creates a db/schema.rb file that is portable against any DB supported by Active Record rake db:schema:load # Loads a schema.rb file into the database rake db:seed # Loads the seed data from db/seeds.rb rake db:setup # Creates the database, loads the schema, and initializes with the seed data (use db:r... rake db:structure:dump # Dumps the database structure to db/structure.sql rake db:structure:load # Recreates the databases from the structure.sql file rake db:version # Retrieves the current schema version number rake dev:cache # Toggle development mode caching on/off rake initializers # Print out all defined initializers in the order they are invoked by Rails rake log:clear # Truncates all/specified *.log files in log/ to zero bytes (specify which logs with L... rake middleware # Prints out your Rack middleware stack rake notes # Enumerate all annotations (use notes:optimize, :fixme, :todo for focus) rake notes:custom # Enumerate a custom annotation, specify with ANNOTATION=CUSTOM rake restart # Restart app by touching tmp/restart.txt rake routes # Print out all defined routes in match order, with names rake secret # Generate a cryptographically secure secret key (this is typically used to generate a... rake stats # Report code statistics (KLOCs, etc) from the application or engine rake task_sample:sample # 実行処理の説明 rake test # Runs all tests in test folder except system ones rake test:db # Run tests quickly, but also reset db rake test:system # Run system tests only rake time:zones[country_or_offset] # List all time zones, list by two-letter country code (`rails time:zones[US]`), or li... rake tmp:clear # Clear cache, socket and screenshot files from tmp/ (narrow w/ tmp:cache:clear, tmp:s... rake tmp:create # Creates tmp directories for cache, sockets, and pids rake yarn:install # Install all JavaScript dependencies as specified via Yarn
確かにdb:migrate
とかありますね。
db:migrateのタスクの中身見てみようとしたけど、パット見ファイルの場所が見つからなかったので、またの機会にします。
wheneverを使用
whenever Gemfileに
gem 'whenever', require: false
を追加して、
$ bundle install $ be wheneverize . [add] writing `./config/schedule.rb' [done] wheneverized!
config/schedule.rb
を開いて
set :output, "log/development.log" every 1.minute do rake "task_sample:sample" end
と書いて、cronを登録する
# 登録します $ bundle exec whenever --update-crontab #これで確認できます $ be whenever * * * * * /bin/bash -l -c 'cd /Users/my0shym/hogeApp && RAILS_ENV=production bundle exec rake task_sample:sample --silent >> log/development.log 2>&1'
$ be rails s
しておいて、別タブで$ tail -f log/development.log
で確認する。
すると、見事Hello Worldが表示されました〜パチパチ
rakeタスクからDBとかにアクセスしたいときは
task :hoge => :environment do
が必要らしい。
と、ここでコロンとアローの使い方がうまく整理でいていないことが発覚したので、今度やる。
twitter分析アプリ作成①
railsにて実装。
グラフの描画はchart.jsを使用。
とりあえずモデル作成
※alias be='bundle exec'
$ be rails g model Person name:text twitter:text university_name:text entry_no:integer grade:integer age:integer $ be rails g model Follower num_of_follower:integer date:datetime person:references $ be rails g model Follow num_of_follow:integer date:datetime person:references $ be rails g model Tweet num_of_tweet:integer date:datetime person:references
twitterのAPI
require 'twitter' client = Twitter::REST::Client.new do |config| config.consumer_key = "YOUR_CONSUMER_KEY" config.consumer_secret = "YOUR_CONSUMER_SECRET" config.access_token = "YOUR_ACCESS_TOKEN" config.access_token_secret = "YOUR_ACCESS_SECRET" end user = client.user('@hogehogetarou') followers = user.followers_count followers = user.friends_count tweets = user.tweets_count
やっぱりDB設計変えたので、こちらは削除する
$ be rails destory model follow $ be rails destroy model follow $ be rails destroy model follower $ be rails destroy model tweet
$ be rails g model Status followers:integer followings:integer tweets:integer favs:integer date:datetime person:references # dbがゴチャついたと思うので、リセット # これはレコードのリセット $ be rake db:reset # これはmigrationを全部最初からやり直す。 $ be rake db:migrate:reset
$ be rails g controller management show new edit
React奮闘記①
メロスと同じくReactがわからぬ。
チュートリアルと、ドットインストールは写経してみたものの、雰囲気しかわからなかった。。。
バスケットをやっているのをルール知らないで外から見ていて、「どうやらあのかごをボールが通ると点数が入るらしい」「なんか移動するときはぼーるをばうんどさせなきゃいけないらしい」くらいにしかつかめなかった。
そもそものJavaScriptが怪しかったので、progateで一通りサクッと復習しといた。
からの、
- 作者: 吉田裕美
- 出版社/メーカー: 秀和システム
- 発売日: 2017/09/16
- メディア: 単行本
- この商品を含むブログ (1件) を見る
これだ。
環境構築する。
Mac High Sierra 10.13.5
一応もう環境はできているはずだが、改めて。
Node.jsのinstall
$ node -v v10.5.0
→OK。すでにあった。
npmのinstall
$ npm -v 6.1.0
→OK。すでにあった。
init
# 作業用ディレクトリにて $ npm init -y
npmパッケージinstall
npm install react react-dom npm install webpack webpack-cli webpack-dev-server --save-dev npm install babel-cli babel-loader babel-preset-env babel-preset-react --save-dev npm install eslint eslint-loader eslint-plugin-react --save-dev npm install css-loader style-loader babel-loader --save-dev
あとは別途設定ファイルを設定。 詳しくは
react_book/install_mac.md at master · yuumi3/react_book · GitHub
より。
webpackとは、、、JavaScript、cssとかのライブラリ、自分で書いたやつをまとめて一つのJSファイルにしてくれるやつ…!!? . . . 2,3時間かけて、
ようやくJSXの基本的なことはわかったような気がする。
コンポーネント - クラスコンポーネントと - 関数コンポーネントがある。
関数コンポーネントはあまり複雑なことはやらせない。
tigでvimじゃなく謎エディタnanoが開いてしまう現象解消
友人に進められシェルを魔改造zshにしたのが原因でtig(やってないけどgit commitコマンドも)のコミットメッセージ編集のところがmac標準搭載らしい謎エディタnanoになってしまっていた。
うまく保存できずにキャッシュファイル的なやつができてaddとかができなくなったりしてしまって面倒くさいので修正。
これを解消するには
git config --global core.editor 'vim -c "set fenc=utf-8"'
これだけ。
macのvagrantでcentos7.2にansible2をinstallしてplay-book実行するまで
Vagrant メモ (1) – 1Q77 Vagrant メモ (2) – 1Q77
これにしたがってvirtualbox,vagrantをインストールしました。
VirtualBoxとVagrantはすでに設定済とします。
VagrantでCentOS7.2を使う。
こちらからほしいOSを探してリンクをコピーします
今回はなんとなくCentOS7.2を使ってみようと思うので、それを探します。・
$ vagrant box add centos7.2 https://github.com/CommanderK5/packer-centos-template/releases/download/0.7.2/vagrant-centos-7.2.box $ vagrant init CentOS7.2 # 適当なディレクトリで実行する $ vagrant up # 起動する $ vagrant ssh # 接続する
これでCentOSサーバに入れました。
参考: VagrantでCentOS7をインストール - Qiita
一方こんなやり方でもいいみたいです。
$ vagrant init --minimal ubuntu/trusty64 # minimalオプションを付けると設定ファイルが最低限のものだけになる。 $ vagrant up $ vagrant ssh
参考: VagrantとDockerについて名前しか知らなかったので試した - Qiita
一度取得したOSは追加のプロセスを経ないで立ち上げることができるっぽいですね。
ただ、どちらの方法でも、すでにboxがローカルになければ、セットアップに数十分くらいかかります。(ました。)
直接urlを指定してboxを追加するのは、CentOSでいうrmp、
名前を指定してboxを(追加した後)iした後するのは、yumで管理する的なことだと勝手に思ってます。
その一覧はどうやって見られるのでしょうか。
$ vagrant box list centos6 (virtualbox, 0) centos7.2 (virtualbox, 0)
ではこのOSたちはどこに保存されているのでしょうか。
標準では/Users/<user>/.vagrant.d/boxes
の下に配置されるようです。
$ pwd /Users/<user>/.vagrant.d/boxes $ tree -s . ├── [ 96] centos6 │ └── [ 96] 0 │ └── [ 192] virtualbox │ ├── [ 258] Vagrantfile │ ├── [ 11372] box.ovf │ ├── [ 26] metadata.json │ └── [ 423996416] packer-centos-6.5-x86_64-disk1.vmdk └── [ 96] centos7.2 └── [ 96] 0 └── [ 192] virtualbox ├── [ 258] Vagrantfile ├── [ 12065] box.ovf ├── [ 650415104] centos-vm-disk1.vmdk └── [ 26] metadata.json
確かにCentOSと思しき容量大きいファイルが存在しました。これらしいですね。
さて、今からansibleを使って一方のサーバーからもう一方のサーバーに処理を流したいので、sshで接続する必要があります。
IPアドレスはどうなっているのでしょうか。
デフォルトではプライベートIPの設定はできていないみたいなので、Vagrantfileを弄る必要があります。
# 以下のように設定 config.vm.network :private_network, ip: "192.168.33.10"
編集後、vagrantを再起動します。
$ vagrant reload
で再起動します。
同様にして同じ構成のサーバーをansibledというディレクトリの中に作ります。
ただしプライベートIPアドレスは192.168.33.11としておきます。
CentOSにansibleをinstallする
ansible用サーバーにて
# yum install epel-release # epelレポジトリを追加 # yum install ansible --enablerepo=epel-testing # ansibleをinstall # ansible --version # versionを確認 ansible 2.4.2.0
enablerepo=epel-testingにしないと、古いversionのansibleがinstallされてしまうということがあるみたいです。(検証してないですが、)
ansibleで構成管理をする
早速ansibleで変更を流してみましょう。
まずは疎通確認から。
ansible 192.168.33.11 -m ping [WARNING]: Could not match supplied host pattern, ignoring: all [WARNING]: provided hosts list is empty, only localhost is available [WARNING]: Could not match supplied host pattern, ignoring: 192.168.33.11 [WARNING]: No hosts matched, nothing to do
おっとこれは早漏でした。
受ける側の設定を何もしていなかったです。
いくら同じネットワーク内だからといって、無許可で流されたらたまったもんじゃないですね。
結局sshで接続することになるので、sshのconfigあたりを設定変更すればいけそうですね。
と思ったら、その前にansible側でもhostの情報を書かないとだめらしいです。
$ vi /etc/ansible/hosts
ここにホスト情報を追加します。
さて今一度疎通確認をしてみる。(受け側の設定何も変えてないのでだめだと思うが。)
# ansible 192.168.33.11 -m ping The authenticity of host '192.168.33.11 (192.168.33.11)' can't be established. ECDSA key fingerprint is 7a:f6:47:1b:a9:04:c8:c6:90:d5:8c:48:14:03:d3:64. Are you sure you want to continue connecting (yes/no)? yes 192.168.33.11 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added '192.168.33.11' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).\r\n", "unreachable": true }
案の定だめでした。認証の部分で失敗しましたね。
認証方法は色々ありますが、今回はansible側の公開鍵を受け側に登録しておくことにします。
ansibleサーバにて
# vagrantユーザーで実行する $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/vagrant/.ssh/id_rsa): # 特に何も入力しないでEnterする Enter passphrase (empty for no passphrase): # 特に何も入力しないでEnterする Enter same passphrase again: # 特に何も入力しないでEnterする Your identification has been saved in /home/vagrant/.ssh/id_rsa. Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub. The key fingerprint is: 6f:9d:ed:39:06:75:70:9b:ff:c0:71:51:ff:00:8a:dc vagrant@localhost.localdomain The key's randomart image is: +--[ RSA 2048]----+ | . o| | . o . ...o| | o E .o=| | o++| | S o +o| | . ..oo .| | o o....| | . .o..| | .o. | +-----------------+ $ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsUSJIsKgxiOiFxh2obSw0RCOmODtyyFS60qr1/phQa35sDJwjcoy1kpBdLvIFeQZiWVmKU+vuz1lNjWekKvSOPmxmW54LAJSnqBpy4JgIXzRrm7kEEi0Ol9rkSG3LShtC89CXqOm+PVgXXXXXXXXXXXXXXXXXXXXXXXXXX0Hj+wBTUYrcvQZ7RDAYA1FQeav0Hj+wBTXXXXXXXXXXXXXXXXXXXXXXXXDAYA1FQeav0HnL1CAnseZtBdxXewh/0A9MU9kygj5G3E1j0ZG0q6l9Pt vagrant@localhost.localdomain # これをコピっとく
受けサーバ側
$ vi ~/.ssh/authorized_keys # 先程コピーした公開鍵を追加する
これにて完了です。
それでは満を持して疎通確認。
$ ansible 192.168.33.11 -m ping 192.168.33.11 | SUCCESS => { "changed": false, "ping": "pong" }
OKなようです。
ということは、普通にssh接続もできるということですね。
$ ssh -i ~/.ssh/id_rsa vagrant@192.168.33.11 The authenticity of host '192.168.33.11 (192.168.33.11)' can't be established. ECDSA key fingerprint is 7a:f6:47:1b:a9:04:c8:c6:90:d5:8c:48:14:03:d3:64. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.33.11' (ECDSA) to the list of known hosts. Last login: Fri Jan 5 19:42:58 2018 from 10.0.2.2
入れました。
さてここからがansibleの出番です。
ansibleのplaybookを作成してみます。
slコマンドをyumでinstallするだけのplaybookとします。
yum.yml
- hosts: all tasks: - name: slコマンドのyumインストール yum: name=sl
$ ansible-playbook yum.yml PLAY [all] ****************************************************************************************** TASK [Gathering Facts] ****************************************************************************** ok: [192.168.33.11] TASK [slコマンドのyumインストール] ***************************************************************************** fatal: [192.168.33.11]: FAILED! => {"changed": false, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": ["Loaded plugins: fastestmirror\n"]} to retry, use: --limit @/home/vagrant/yum.retry PLAY RECAP ****************************************************************************************** 192.168.33.11 : ok=1 changed=0 unreachable=0 failed=1
おっと、yumはrootじゃないと使えないみたいです。
sudo: yes
を書き加えるだけでいいみたいです。
- hosts: all sudo: yes tasks: - name: slコマンドのyumインストール yum: name=sl
さて、いざ実行
$ ansible-playbook yum.yml [DEPRECATION WARNING]: Instead of sudo/sudo_user, use become/become_user and make sure become_method is 'sudo' (default). This feature will be removed in version 2.6. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. PLAY [all] ****************************************************************************************** TASK [Gathering Facts] ****************************************************************************** ok: [192.168.33.11] TASK [slコマンドのyumインストール] ***************************************************************************** changed: [192.168.33.11] PLAY RECAP ****************************************************************************************** 192.168.33.11 : ok=2 changed=1 unreachable=0 failed=0
OKっぽいですね。
実際に受け側のサーバーで確認してみます。
(@@) ( ) (@) ( ) @@ () @ O @ O @ ( ) (@@@@) ( ) (@@@) ==== ________ ___________ _| |_______/ \__I_I_____===__|_________| _)--- | H\________/ | | =|___ ___| _________________ | | H | | | | ||_| |_|| _| \_____A | | H |__--------------------| [___] | =| | _______|___H__/__|_____/[][]~\_______| | -| | | |-----------I_____I [][] [] D |=======|____|________________________|_ | o |=-~~\ /~~\ /~~\ /~~\ ____Y___________|__|__________________________|_ |___|= || || || |_____/~\___/ |_D__D__D_| |_D__D__D_| \O=====O=====O=====O_/ \_/ \_/ \_/ \_/ \_/
ちゃんとシュポってますね。
ということで、一旦ansible導入は一区切りつけたいと思います。
次回はplaybookのroleとかの使い分けを整理していきたいです。
macでインカメをコマンドラインから使用する方法を探したい①
Macのカメラからjpg画像を定期的に取得してローカルなりなんなりに保存したい。
検索する
「mac カメラ 定期的に」
ぱっと見
コマンドライン
Mac OSX で web カメラ撮影をコマンドラインで行う方法のメモ|毎日の向こうに
このサイトで、以下のツールが紹介されている。
isightcapture for Mac : Free Download : MacUpdate
しかしまあ、OSのバージョン10.3の時代かぁ。。。レオパードだと。
記事を見てみると、2005年だしなぁ。
しかもなんか怪しいとも言えなくもない。
毎度のことなのだが、こういうソフトの怪しい怪しくない、大丈夫なのかだめなのかの見極め方がつかめていないマン。
でも31,455もダウンロードされている。これは信じていいのか。
シェルスクリプト
Macで自動で定期的にスクリーンショットを撮るシェルスクリプト - yumulog | 社会人博士の日記
細かく見てないけど、できそうだということだけ認識しておく。
↓
これはカメラじゃなくて、スクリーンショットだった。
Automater
http://apple.memoblog.net/205/
これ普通に簡単そう。
記事もあまり読まずに、直感でAutomater触ってみることに。
↓
Automaterの闇にハマった。
よくわからない。
photoboothの位置付がわからなくなってきた。
Automaterはフォルダアクションとかには便利っぽいけど、特定のアプリの特定の動きみたいな小難しいことは面倒くさいっぽい。
もうシェルスクリプトで書いてみちゃったほうがいい気がする。
調査に時間をかけすぎている。
↓
それもなかなか情報がない。
そもそもphotoboothなんて使っているやつはこの世界にはいない。
↓
そもそもの方針が間違っているような気がしてきた。
「カメラ mac 自動」
再検索。
微妙に違う。
「インカメラ mac 自動」
これもあまりいい情報がない。
やはり一番最初のコマンドラインツールを使ったほうがいいのではないか。
ダウンロードページへ
↓
おいおい、ちょっと待てなんか登録しないとだめなのか?
↓
しゃあなし「isightcapture」でググってみる。
GitHub - RandyMcMillan/iSightCapture
↓
それっぽいのダウンロードできそうなページがあったが、これは流石にきな臭すぎる。
[ttp://download.cnet.com/isightcapture/3000-2150_4-72546.html]
↓
vgyazo: gyazoとisightcapture組み合わせてみた - はてなの鴨澤
求めていたものとは違うが有益っぽい情報出てきた。
そうか、Macのカメラのことをhttp://d.hatena.ne.jp/kamosawa/20091222/1261473923
isightcapture(http://www.intergalactic.de/pages/iSight.html)ってのは、Macに付属しまくってるiSightってカメラで写真を1枚撮ってセーブする、というだけのコマンドラインツール。
残念ながらurlは無効だった。
デフォルトで使えるコマンドってわけではなさそうだった。
それっぽいのがあるかなと検索してみる。
「isightcapture mac」
GitHub - RandyMcMillan/iSightCapture
これクローンしたらいいのかなーと思って読んでみると、これは動画からキャプチャするやつってことか...?
isight
Macのコマンドラインツールということで、「brew isightcapture」で検索
↓
isight からコマンドラインで画像をとりこむには imagesnap - tokuhirom's blog
ありがた過ぎる情報出現!
$ brew install imagesnap
これにて解決できそうです!
$ imagesnap Capturing image from device "<AVCaptureDALDevice: 0x9fc4daf24440 [FaceTime HD Camera][0x1410000005ac8908]>"...
さてはて、保存先はどこなのだろうか。
「"imagesnap" 保存先」
調べによると、/usr/local/bin/imagesnapと同じフォルダにsnapshot.jpgという名前のファイルができるとな。
できないとな。
永遠にできなかったので調べてみると
Does not work on High Sierra · Issue #16 · rharder/imagesnap · GitHub
やはりHigh Sierraでは保存されないとのissueが上がっている。
OSとXcodeを再インストールしたらできたと言ってる人がいたが、OS再インストールは辛い。
自分もissue投げてみるか。。。
結局解決できず、諦めることに。。。
macOSのアプリを作ってみるかな・・・
頓挫しました。 このissueが解決されるまで待ちます。