プログラマ・アゲイン blog

還暦を過ぎたけどプログラマ復帰を目指してブログ始めました

Ruby on Railsを勉強中に遭遇した問題(4)

前回の「Ruby on Railsを勉強中に遭遇した問題(3)」の続きになります。

テキストとして使用している「Ruby on Rails 6 超入門」の、第5章「その他に覚えておきたい機能」の「Reactとの連携」以降で遭遇したものです。

ただ、「Reactとの連携」については Rails 7 で大きく変わっているため、テキストと同じようなことを別の方法で試しています。

テキストに従ってやっていくと、テキストには書かれていない問題にいろいろ遭遇しました。

ここでは、遭遇した問題について、内容と対応を記録したいと思います。

 

 

Reactとの連携

Yahoo!ニュース・ヘッドラインを表示しよう!

REXML::ParseException

テキストと同じように、ajaxアクションメソッドをコーディングしたところ、いきなり以下のエラーが出ました。

「Missing end tag for 'link'」で Webをググッても、ピッタリのものはヒットしません。

ただ、url が関係することもあるという事なので、url 'https://news.yahoo.co.jp/pickup/rss.xml' を実際にブラウザーで確認してみると、存在していませんでした。

どうやら、url が変更になったようです。

yahoo の rss は以下のページにまとまっていました。

RSS一覧 - Yahoo!ニュース

その中の、「主要 - トピックス」にアクセスしてみると、url は「https://news.yahoo.co.jp/rss/topics/top-picks.xml」になっています。

この url で ajaxアクションメソッドを修正しました。

  def ajax
    url = 'https://news.yahoo.co.jp/rss/topics/top-picks.xml'
    uri = URI.parse(url)
    response = Net::HTTP.get_response(uri)
    render plain:Hash::from_xml(response.body).to_json
  end

アクセスし直すと、正常に動作しました。

dummy_data.js を修正する

dummy_data.js (jsxからjsに変更) についても、今までの経験からテキストのコードを変更しました。

また、表のヘッダーにタイトルが出なかったり、各記事にリンクが張られていなかったりしたところも変更しました。

変更後のソースは、以下のようになりました。(変更部分を中心に抜粋)

・・・
import {createRoot} from "react-dom/client"
・・・
target_dom = document.querySelector('#data');
const root = createRoot(target_dom);
・・・
function getData(f) {
    let url = "http://localhost:3000/data/ajax";
    if (f != '') {
        url += '?name=' + f;
    }
    fetch(url)
    .then(
        res => res.json(), (error) => {
            const el = (<p>ERROR!!</p>);
            root.render(el);
        }
    )
    .then(
        (result) => {
            console.log(result);
            let arr = [];
            for(let n in result.rss.channel.item) {
                let data = result.rss.channel.item[n];
                arr.push(
                    <tr key={n}>
                        <th><a href={data.link}>{data.title}</a></th>
                        <td className="small">{data.pubDate}</td>
                    </tr>
                );
            }
            const el = (
                <table className="table mt-4">
                    <thead className="thead-dark">
                        <tr>
                            <th><a href={result.rss.channel.link}>{result.rss.channel.title}</a></th>
                            <th>Date</th>
                        </tr>
                    </thead>
                    <tbody>{arr}</tbody>
                </table>
            );
            root.render(el);
        },
        (error) => {
            console.log(error);
            const el =(<p>ERROR!!</p>);
            root.render(el);
        }
    );
}

 

Deviseでユーザー認証を行なおう

NoMethodError in Devise::RegistrationsController#create

Sign up しようとしたら、エラーになりました。

エラー・メッセージの中で、「undefined method `account_url' for #<Devise::RegistrationsController:0x0000000000c2b0>」という記述が有ります。

Webでググると、ヒットしました。

https://abillyz.com/vclbuff/studies/460

Deviseのリポジトリに次のIssueが作成されていました。
Devise 4.8.1 + Rails 7.0.0 | Undefined method 'user_url' #5439
Rails 7 で実装された Hotwire との相性による問題みたいです。
解決方法については nickrivadeneira氏のコメントで簡潔に記載されています。
config/initializers/devise.rbの266行目あたりにあるconfig.navigational_formatsのコメントアウトを解除して設定を記述します。

という事で、config/initializers/devise.rbの266行目あたりにあるconfig.navigational_formatsのコメントアウトを解除して、以下のように変更しました。

  config.navigational_formats = ['*/*', :html, :turbo_stream]

Rails Server を立ち上げ直して再度登録しようとしましたが、今度はエラーにならず画面も変化しません。Rails Server のログを見ると、以下のようになっているので既に登録されていたのだと思います。

  TRANSACTION (0.2ms)  begin transaction
  Account Exists? (0.4ms)  SELECT 1 AS one FROM "accounts" WHERE "accounts"."email" = ? LIMIT ?  [["email", "taro@yamada"], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  rollback transaction

試しに登録したユーザーでログインしたところ、正常にログインできました。

また、アカウントが作成された時刻がエラーになった時の時刻のようなので、やはりデータとしては登録されていたのだと思います。

Routing Error

ログアウトしようとすると、以下のエラーになります。

エラー・メッセージの中で、「No route matches [GET] "/accounts/sign_out"」と記述されているので、config/routes.rb を確認しました。

Rails.application.routes.draw do
  get 'hello/index'
  get 'hello/login_check'
  devise_for :accounts
end

また、rails routes でも確認しました。

                        Prefix Verb   URI Pattern                           Controller#Action
                   hello_index GET    /hello/index(.:format)                hello#index
             hello_login_check GET    /hello/login_check(.:format)          hello#login_check
           new_account_session GET    /accounts/sign_in(.:format)           devise/sessions#new
               account_session POST   /accounts/sign_in(.:format)           devise/sessions#create
       destroy_account_session DELETE /accounts/sign_out(.:format)          devise/sessions#destroy
          new_account_password GET    /accounts/password/new(.:format)      devise/passwords#new
         edit_account_password GET    /accounts/password/edit(.:format)     devise/passwords#edit
              account_password PATCH  /accounts/password(.:format)          devise/passwords#update
                               PUT    /accounts/password(.:format)          devise/passwords#update
                               POST   /accounts/password(.:format)          devise/passwords#create
   cancel_account_registration GET    /accounts/cancel(.:format)            devise/registrations#cancel
      new_account_registration GET    /accounts/sign_up(.:format)           devise/registrations#new
     edit_account_registration GET    /accounts/edit(.:format)              devise/registrations#edit
          account_registration PATCH  /accounts(.:format)                   devise/registrations#update
                               PUT    /accounts(.:format)                   devise/registrations#update
                               DELETE /accounts(.:format)                   devise/registrations#destroy
                               POST   /accounts(.:format)                   devise/registrations#create

確かに、「 [GET] "/accounts/sign_out"」は無く、sign_out は DELETE しか有りません。

Webでググると、これもヒットしました。

[Rails]No route matches [GET] "/users/sign_out”の対処法 - Qiita

sign_out時のメソッドがDELETEからGETに変更されているので(いつなったのかは把握できていない)、変更すれば解決しそう。

ということで、同じようにconfig/initializers/devise.rb を編集して、Rails Server を立ち上げ直すと sign_out できました。

 

新メッセージボードを作ろう

LoadError in Device::SessionsController#new

/borad_messages にアクセスしたら、以下のメッセージが出ました。

Rails Server のログにも、同様のエラー・メッセージが出力されています。

Started GET "/board_messages" for ::1 at 2022-11-17 15:38:09 +0900
  ActiveRecord::SchemaMigration Pluck (0.6ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by BoardMessagesController#index as HTML
Completed 401 Unauthorized in 26ms (ActiveRecord: 0.0ms | Allocations: 3010)

Started GET "/accounts/sign_in" for ::1 at 2022-11-17 15:38:09 +0900
Processing by Devise::SessionsController#new as HTML
  Rendering layout layouts/application.html.erb
  Rendering devise/sessions/new.html.erb within layouts/application
  Rendered devise/shared/_links.html.erb (Duration: 3.4ms | Allocations: 736)
  Rendered devise/sessions/new.html.erb within layouts/application (Duration: 23.9ms | Allocations: 4240)
  Rendered layout layouts/application.html.erb (Duration: 78.5ms | Allocations: 9697)
Completed 500 Internal Server Error in 131ms (ActiveRecord: 0.8ms | Allocations: 19266)

LoadError (cannot load such file -- sassc):
app/views/layouts/application.html.erb:10

Devise によるログイン処理の時には引っかからなかったのに、今度は引っかかったようです。

Webでググると、これもヒットします。

rails 7.00における "cannot load such file --sassc"の解決法 - Qiita

このページで説明されているように、Gemfile の 以下の部分をコメントアウトし、bundle install しました。

# Use Sass to process CSS
gem "sassc-rails"

 

c:\Data\Web_study\Rails\RailsDeviseApp>bundle install
・・・
Using sassc-rails 2.1.2
・・・

Rails server を立ち上げて再度アクセスすると、正常に Log in 画面が表示されました。

NoMethodError in BoardMessagesController#index

Log in しようとすると、以下のエラー画面が表示されました。

「undefined method `id'」と言われているので、board_messages_controller.rb の「@board_user.id」のことだと思います。

そこで、「logger.debug(@board_user.inspect)」を直前にコーディングして、@board_user の内容を確認してみました。

すると、Rails server のログには、以下のように出力されました。

#<ActiveRecord::Relation [#<BoardUser id: 7, nickname: "<<no name>>", account_id: 7, memo: nil, created_at: "2022-11-18 01:34:55.337093000 +0000", updated_at: "2022-11-18 01:34:55.337093000 +0000">]>

「<ActiveRecord::Relation [・・・]」となっています。

board_messages_controller.rb を確認すると、以下のようにユーザーが既にいた時(9行目)と新規の時(15行目)で、users へのデータのセットの仕方が違っています。

 9    users = BoardUser.where('account_id == ?', current_account.id)[0]
・・・
15      users = BoardUser.where 'account_id == ?', current_account.id

15行目の書き方では配列になってしまうので、15行目を 9行目と同じにしました。

結果として、Rails server のログには以下のように出力され、エラーにならず正常に処理されました。

#<BoardUser id: 8, nickname: "<<no name>>", account_id: 8, memo: nil, created_at: "2022-11-18 01:38:04.076129000 +0000", updated_at: "2022-11-18 01:38:04.076129000 +0000">

 

以上、Ruby on Rails を勉強していく中で、いろいろ経験することができました。

切りがいいので、続きは別のページに載せていきたいと思います。