Giter Club home page Giter Club logo

touhyosan's Issues

「投票を作成」ボタンを押した後のフォームにおいて、選択肢の順序を入れ替える毎、また「登録する」ボタンを押したときに、投票が作成される

以下のcommitに対するバグ報告です。

d75e2cc

以下のルーティングが設定されているため、フォームでsubmitした場合、POST /polls/:poll_id/votes  polls/votes#createが該当する。

Prefix Verb URL コントローラ#アクション
root GET /   polls#new
poll_votes   POST /polls/:poll_id/votes(.:format)   polls/votes#create
new_poll_vote   GET /polls/:poll_id/votes/new(.:format)   polls/votes#new
edit_poll_vote GET   /polls/:poll_id/votes/:id/edit(.:format) polls/votes#edit
poll_vote   PATCH   /polls/:poll_id/votes/:id(.:format)   polls/votes#update
  PUT     /polls/:poll_id/votes/:id(.:format)   polls/votes#update
polls   POST /polls(.:format) polls#create
new_poll   GET   /polls/new(.:format) polls#new
poll   GET /polls/:id(.:format) polls#show

選択肢の順番の入れ替えをフォーム上で行う場合、デフォルトのルーティングから外れることにつなばるので、以下の点を仕様として検討、決定しておく必要があるのではないでしょうか。

  1. UI
    1. いつ登録するののか(「登録する」ボタンを押した時なのか)- ここで登録するというのは、単にサーバに送信するか否かではなく、サーバ上で投票を確定したものとして扱うか否かを指します。
      1. newアクションの時に、デフォルト値でレコードを新規登録すると、「登録する」ボタンを押すと、直前の選択肢の順番入れ替えの場合と同一内容をサーバに送ることになる。
        1. ただし、「登録する」ボタンがないと、選択肢の順番を入れ替えずにそのまま登録するということが出来なくなる。
        2. また、デフォルト値でレコードを新規登録する場合、デフォルト値が選択肢のスコアに影響を与えないようにしなければならない(デフォルト値として0点を与える、デフォルト値の場合はスコアの計算に利用しないなど)
    2. (キャンセル出来るのか)
      1. 「登録する」ボタンを押した時に登録される場合、「登録する」ボタンを押す前にフォームを閉じると、キャンセルと同等の効果がある。
      2. newアクションの時に、デフォルト値でレコードを新規登録すると、単にフォームを閉じた場合に、レコードが削除されずに残ってしまう。
  2. ルーティング
    1. 既存のルーティングを利用するか
      1. 利用しないルーティングが出てきたらどうするか
    2. 独自のルーティングを設定するか
  3. アクション
    1. 既存のアクションの処理内容を変更するか
    2. 独自のアクションを作成するか

vote/create, vote/updateのフラッシュメッセージが次にvote/create, vote/updateが実行されるまで表示され続けている

現在のtouhyousanのフラッシュメッセージは、もともと意図していたものとは、異なる挙動になっていると思います。

turbo_driveを利用していた場合は、意図通りだと思うのですが、turbo_frame, turbo_streamで画面遷移をしない場合は、ずっと表示されっぱなしになっています。

また、さらに非同期にブロードキャストで変更されると、フラッシュメッセージが何を伝えるのか分からなくなると感じています。

DB保存時DBカラム制約違反で500エラーページが表示されないという問題

Hotwire.love meetup Vol.21(2023-09-14)のフリートークにて、「Modelに対するValidation定義とは異なるDBのカラム制約を与えた状態で、DBに保存するときに制約違反が発生しても、500エラーページとして表示されない」というテーマで盛り上がりました。
ただし、最終的な結論がでずに時間切れとなりました。
今まではsave!メソッドを呼び出し、制約違反の例外が発生したらエラーページが表示されていたが、最近画面が何も変化しないことに遭遇した、Turboが握りつぶしているのではないかという疑問でした。
いくつかのやり方でコード変更し、挙動が変わることは確認しましたが、なぜエラーページが表示されないかには辿り着けませんでした。
勉強会の後、Railsのエラーページ表示の仕組みを色々調べて、やっと腑に落ちる状態になりました。フリートーク中に出された色々な仮説に基づくコード変更の根拠が理解出来るようにはなったのですが、今まで出来ていたのに最近できなくなったというという事に対しては、説明できないとも感じました。

そこで思いついたのは、「実はDBカラムに対する制約違反は発生していない」という仮説です。
そもそも制約違反が発生していないのならば、エラーページは表示されません。
「制約違反が発生している」という前提で話していましたが、db/schema.rbをみて確認したり、railsのコンソールでsaveメソッドを呼び出して例外が発生するのかを確認してはいませんでした。またValidationが通った後にDBに保存するのですから、Validationが通らなかった場合は、保存しないため制約違反も発生しません。

実際に、Ruby 3.2.2, Rails 7.0.8、PostgrSQLにて

rails g scaffold blog title:string content:

とし、db/schema.rbが以下の通りになるようにmigrateして、試してみました。

ActiveRecord::Schema[7.0].define(version: 2023_09_17_002252) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "blogs", force: :cascade do |t|
    t.string "title", null: false
    t.text "content", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

簡単にするため、Modelに対してはValidationを定義しませんでした。
Not Null制約を与えているので、blog_paramsではなく(フォームから送信されたパラメータでは値がnilではなく空文字列になってしまうため)明示的に値がnilであるハッシュをsaveメソッドに与えて呼び出しました。

  def create
    hash = { title: nil, content: nil }
    # @blog = Blog.new(blog_params)
    @blog = Blog.new(hash)
    # raise
    # @blog = Blog.find(100)
    # @blog.save!   # (A)
    respond_to do |format|
      if @blog.save  # (B)
      # if @blog.valid? # (A)の場合はこちらを有効にしました
          format.html { redirect_to blog_url(@blog), notice: "Blog was successfully created." }
        format.json { render :show, status: :created, location: @blog }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

結果は、(A)の場合はsave!メソッド呼び出し時、(B)の場合saveメソッド呼び出し時に、以下の例外が発生しエラーページが表示されました。

ActiveRecord::NotNullViolation in BlogsController#create

saveメソッドはDB保存に成功したらtrue、失敗したらfalseを返します。
Validation結果はerrorsに格納されています。

save!メソッドは、DB保存に失敗したら、RecordNotSavedエラーをraiseします。
saveとsave!の差は成功、失敗を値として返すか、失敗時に例外をraisesするかであり、呼び出し先でraiseされた例外はrescueしないようです。

スコアが同点の場合(特に上位3つの枠からあふれた場合)の扱いについて

選択肢の個数分の投票数があった場合、すべての選択肢のスコアが同点になるケースが考えられます。
現在は上位3つを選ぶという仕様ですが、例えば4つの選択肢があった場合に、すべてスコアが同点の場合にどうするかということです。
これは事前にどう扱うかを決めておくという問題ですので、備忘のために登録しておきます。

debug.cssの導入

「猫でもわからHotwire入門 Turbo編」で紹介されていたのですが、以下のCSSを適用すると、turbo-frame領域に枠が表示されます。 
デバッグ時には有用化と思い提案します。

debug.css

Rails Mermaid ERD gemを用いて、DBのERD図を作成、表示させる

RailsのER図をMermaidで柔軟に生成できるGemを作りました
GitHub - koedame/rails-mermaid_erd: Generate Mermaid ERD from your Ruby on Rails application.

Gemfileにgemを指定して、bundle install後、以下を実行すると、mermaid_erd/index.htmlが生成されます。

bundle exec rails mermaid_erd

HTMLファイル1個のみですが、JavaScript用いて、いろいろなパターンで表示できます

勉強会のモブプロの成果を直接このリポジトリのブランチに対してpushできないか

現在、モブプロをする場合は、ドライバー役が、hotwire-love/touhyousanをフォークし、フォークしたリポジトリをローカルにクローンし、ローカルに対してコミットした後、勉強会終了後にフォーク先にプッシュし、そしてhotwire-love/touhyousanにプルリクエストすることになっています。
ただしこのやり方の場合、プルリクエストを送ってから、mainブランチにマージされるまでに時間がかかると、勉強会参加者が後日勉強会で行った内容を確認しようと思っても、なかなか確認することができません。
mainブランチにマージする際には、勉強会で行ったことそのままではなく、整理・修正したほうがいい場合もあると思います。
ただ勉強会で行ったことを確認したい場合には、(整理・修正されていなくて)そのままの状態であっても、すぐにみることができたほうが嬉しいと思います。

このため、各勉強会毎にhotwire-love/touhyousanにモブプロ用のブランチを切り(例:vol12)、そこに一旦モブプロ時のcommitをpushし、勉強会の終わりに、その回のモブプロ用のブランチから、mainブランチへのマージ用のブランチを切り(例:vol12_pr)、そのブランチに対するプルリクエストを送って、それをmainブランチにマージしてはどうでしょうか。
vol12_prは作業用のブランチですので、mainブランチにマージした後は削除してかまわないと思います。
逆にvol12のほうは、ある程度の期間は残しておいた方がいいと思います。

投票作成後の「投票を作成」リンクが普通のリンクになる

app/views/polls/votes/result.turbo_stream.erbで表示されるTurboStreamsとしてreplaceされた「投票を作成」リンクが、turbo_frameタグに囲まれていないため、replace後は単なるテキストリンクになっている。
replaceされる対象として、「投票を作成」リンクをturbo_frame_tagで囲んでおく必要がある。

choice毎のstatusの小計を一度に取得するSQL文

touhyousanでpoll_idが指定された場合に、choice毎のstatusの値の個数を取得する。
touhyousanの仕様から、必ず全てのchoiceについてstatusが設定されるので、choicesテーブルに対して、vote_detailsテーブルをinner joinして求めてみた。
ただし、3種類あるstatusの値すべてが設定されるとは限らないため、プログラム中で指定されていないstatusの値を確認する必要がある。
また、order by は人間がselect結果を見やすくするためのもので、プログラムでは必要ないと思う。

select vd.choice_id, vd.status, count(vd.choice_id) from choices as c inner join vote_details as vd on c.id = vd.choice_id where c.poll_id = 54 group by vd.choice_id, vd.status order by vd.choice_id, vd.status;
choice_id | status | count
-----------+--------+-------
161 | 0 | 2
161 | 1 | 1
161 | 2 | 4
162 | 0 | 1
162 | 1 | 1
162 | 2 | 5
163 | 0 | 2
163 | 2 | 5

環境変数REDIS_URLが設定されていないと、bin/setupでエラー発生

$ bin/setup
== Installing dependencies ==
The Gemfile's dependencies are satisfied
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.11s.

== Preparing database ==
rails aborted!
KeyError: key not found: "REDIS_URL"
/home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/cable.yml:11:in fetch' /home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/cable.yml:11:in

'
/home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/environment.rb:5:in `'
Tasks: TOP => db:prepare => db:load_config => environment
(See full trace by running task with --trace)

== Command ["bin/rails db:prepare"] failed ==

draggableから別のライブラリに乗り換える

draggable、2年半くらい前に shopify が手を引いて、引き継ぐ
メンテナが現れず、開発が(ほぼ)停止している ので、替わりのライブラリ
(Sortable etc)にしたほうがよいかもしれません。

#52

とのことなので、別のライブラリに乗り換えた方がいいかもしれませんね。

このままdraggableで作っていってもいいかもしれないけど、開発が進めば進むほど乗り換えが大変になるので、やるなら「今でしょ!」かもしれない。

config/cable.ymlのproductionの定義を#でコメントアウトしても、bin/setup実行時にエラー発生

bin/setup
== Installing dependencies ==
The Gemfile's dependencies are satisfied
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.17s.

== Preparing database ==
rails aborted!
KeyError: key not found: "REDIS_URL"
/home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/cable.yml:11:in fetch' /home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/cable.yml:11:in

'
/home/ykominami/cur/rails7/HotWire/hotwire.love/hotwire.love/touhyosan/config/environment.rb:5:in `'
Tasks: TOP => db:prepare => db:load_config => environment
(See full trace by running task with --trace)

== Command ["bin/rails db:prepare"] failed ==

npmのバージョンにより、rails new --css=bootstrap がエラーになる場合がある

直接touhyousanとは関係ないのですが、touhyousanで利用しているbootstrapをrails newで指定してRailsアプリケーションを新規作成しようとすると、最終的にnpmがエラーを返して失敗します。
具体的にはnpmに対して、package.jsonファイルのscriptsフィールドに以下の内容を追加する時にエラーになります。

npm pkg set scripts.watch:css="nodemon --watch ./app/assets/stylesheets/ --ext scss --exec "yarn build:css""

はnpmに対するコマンドのUSAGEエラーになります。
ここで、以下のようにシングルクォートで囲むとエラーにならなくなります。

--exec 'yarn build:css'

エラー発生を確認したのは、Windows 10のWSL2でdebianパッケージの場合です。
asdfでruby, nodeをバージョン管理しています。
Ruby(3.0.2, 3.1.2, 3.2.2),Rails(7.0.8, 7.0.2.3), node(14.17.0, 17.1.0, 18.12.1, 19.8.1)のどの組み合わせでもエラーが発生しました。

エラーが発生しなかったのは、Mac OS Montley 12,6.9 の場合でした。
こちらもasdfでRuby, Nodeをバージョン管理していました。
こちらはどの組み合わせでもエラーが発生しましませんでした。
ただしnpmのバージョンは6.14.18でした。

そこで、Windows 10, WSL2でもnpmのバージョン6.14.18をグローバルにインストールして実行すると、エラーが発生しなくなりました。

npmのバージョン6.14.18から最新版(10.1.0)のどこからエラーが発生するかは未確認です。

npm pkg set <key>=<value>

において、を""で囲んだ時に、その中でさらに文字列を""で囲むことが、npmの新しいバージョンで認められなくなっているようです。具体的にどのバージョンから認められなくなったかまでは確認できていません。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.