P学習帳

書いておぼえるブログ

Mac OSをアップデートするとMySQLがクラッシュすることがあるらしい?

状況  

Mac OSのアップデートを実行、再起動後、MySQLが起動しなくなった。  

現象  

pidが消えた。エラーがたくさん出る。ググりまくって試行錯誤するものの解決できず。結局、MySQLのバージョンをあげたら再インストールできた。しかしバージョンをあげたことによって違う問題がでてきたりと、大変。  

雑感  

DBがポシャると開発できなくなるので大事。Dockerイメージつくっておいてクシャッたらいちから立て直すみたいなことができるようにしておきたいと思った。解決しないトラブルシューティングに何時間も費やすと心身の消耗が激しい。

入力フォームの値が以前のデータと同じだったら送信をキャンセルさせたい

状況  

何らかのデータを更新するためのフォームがあるとして、入力された値が以前と同じ状態で送信されたらリクエストをキャンセルさせたい。  

コード  

$('input[type="test"]').on('submit', function(e) {
  var prev_val = $('.prev_val');
  var new_val = $('.new_val');
   if ( prev_val == new_val ) {
     e.preventDefault();
     alert('同じ内容です。');  
  }
})

DEMO

codepen.io

雑感  

jQueryでテキストを取得する場合、pタグはtext()、inputタグはval()と使い分ける。間違えやすい。

【Ruby on Rails】capistranoによる自動デプロイ環境でタスクを定期実行させたい

状況  

何らかのバッチ処理を本番サーバーで定期実行させたい。capistranoによる自動デプロイのついでにバッチ処理の設定もしてしまいたい。  

前提  

方法  

capistrano  

capistranoの設定ファイルにwheneverの設定を追記する。   

deploy.rbなどに以下を加える。

set :whenever_command, "bundle exec whenever"
require "whenever/capistrano"

環境を指定するには  

set :environments "production"

とすることでRAILS_ENV=production ~相当のcronジョブが生成される。stagingで実行したいときは置き換えること。   複数の環境を設定する方法があるとおもうが、わからなかった。

whenever

そしてschedule.rbに定期実行したいジョブを加える。

every 1.day, :at => '00:00 am' do
   runner "SomeStuff.new.delay.awesome_procedure"
   rake "jobs:work"
 end

runner "SomeStuff.new.delay.awesome_procedure"は、delayed_jobsにキューを入れる。 次のrake "jobs:work"でキュー入りしたジョブを取り出す。  

キューするときに実行タイミングを引数で指定できる。    

runner "SomeStuff.new.delay(run_at: 1.hour.from_now).awewome_procedure"

デキューされた1時間後にawesome_procedureが実行されることになる。  

雑感

わかってしまえばシンプルに記述できるが、わかるまでが大変。

【RoR】モデルの属性を更新するフォームをつくりたい

状況  

ユーザーのフォーム入力に従ってモデルの値を更新したい。  

やり方  

  • ビューでform_forを使う。  

  • コントローラーでstrong parameterを使ってパラメーターをフィルターする。  

  • モデルの更新  

前提

更新対象のモデル:article title属性をもつ。これを更新したい。

コード  

ビュー  

= form_for @article, url: "/article/update_article_title" do |f|
  =f.text_field :title, value: @article.title

p

コントローラー  

def update_arcicle_title
   return 404 is !update_params[:title]
   article = Article.find(update_params[:id])
   if article.present?
     article.update_attributes(title: update_params[:title])
   end
   redirect_to index_path
end

private
def update_params
   params.require(:article).permit(:title)
 end

ビューから渡ってくるパラメーターについて  

ビューの

= form_for @article, url: ...

に入力&送信されたパラメーターは次のようなハッシュとなる。

article { :title => "great article" }

これをストロングパラメーターでフィルターしたい。 requirepermitで二段階にフィルターする。はじめはモデル名、次に属性名で絞り込む。

params.require(:article).permit(:title)
# => "great article"

エンターキーが押された時のページ遷移を防ぎたい

状況

任意のテキストボックスに何か文字列を入力していて、入力を確定するつもりでエンターを押したら、意図せず変なところにジャンプしてしまうのを防ぎたい。

コード  

$('input[type="text"]').on('keypress', function(e) {
  if( e.which == 13 ) {
     e.preventDefault();  
   }
});

DEMO

codepen.io

thisを関数に渡したい

状況  

jsでthisを関数の引数として渡したい。 しかしそのまま引数の名前をthisとするとエラーになる。予約語だから引数の名前にはできないのだ。  

かわりに_thisとすればよい。  

コード    

$('input[type="text"]').on('click', '#mandatory', function() {
   do_something(this);
}

function do_something(_this) {
  // なんかの処理
}

DEMO

codepen.io

【ActiveRecord】3つ以上のテーブルをJOINしたい

状況

3つ以上のテーブルをJOINしたい。

想定するモデル

記事、段落、文といったモデルを考えてみる。記事は複数の段落を含む。段落は複数の文を含む。以下のモデルがあるものとする。   

# articles
has_many :paragraphs

# paragraphs
belongs_to :article
has_many :sentences
 
# sentences   
belongs_to :paragraph

 

書き方

A) 特定のsentenceが所属するarticleを取得する(孫から先祖へ)。

Sentence.eager_load(paragraph: :article).where(sentences: {id: ?})

B) 特定のarticleに含まれるsentencesを取得する(先祖から孫へ)。

Article.eager_load(paragraphs: :sentences)
       .where(articles: { id: ? })

whereにはテーブル名につづけてハッシュでカラムと値を指定する。テーブル名を渡さないとエラーになる。

OK

.where( sentences: { id: ? })

NG

.where( id: ? )

どのテーブルのidなのかがわからないからダメ。

SQLなら

上記コードから以下のクエリが生成される。  

A)

SELECT * 
FROM sentences 
  LEFT OUTER JOIN paragraphs
    ON paragraphs.id = sentences.paragraph_id
  LEFT OUTER JOIN articles
    ON paragraphs.article_id = articles.id
  WHERE sentence.id = ?

B)

SELECT * 
FROM articles 
  LEFT OUTER JOIN paragraphs
    ON articles.id = paragraphs.article_id
  LEFT OUTER JOIN sentences
    ON paragraphs.id = sentences.paragraph_id
  WHERE sentence.id = ?

モデル名、単数/複数?

複数形または単数形のどちらにするのかはモデルの関連付けに従う。
たとえば上記 B)の場合、Articleは複数のParagraphsをもつので、eager_loadの第一引数は複数形のparagraphsとする。同じように、paragraphsは複数のsentencesをもつので、第二引数も複数形のsentencesとする。   

もっとJOINしたい

たとえば記事の筆者も表示したくなったとする。そのためにauthorsモデルを追加でJOINしたい。このとき、任意の著者によるsentence、paragraph、articleは次のようにして取得できる。

Sentence.eager_load(paragraph: {article: :author})
.where(authors: {name: ?})

モデル名をハッシュでネストすればOK。  

(paragraph: {article: :author})

雑感

Railsガイドに複数モデルの関連付けの方法が紹介されている。読んでもわからなかったので、色々ググって3つ以上のテーブルをつなぐ記法を調べる必要があった。 

Active Record クエリインターフェイス | Rails ガイド

Active Recordの記法がわからない場合、生SQLを食わすという手段もある。

https://railsguides.jp/active_record_querying.html#sql%E3%81%A7%E6%A4%9C%E7%B4%A2%E3%81%99%E3%82%8B

find_by_sqlに生クエリを渡して実行するやり方についてメモした。

gijutsumemo.hatenadiary.jp