Ruby on Railsを勉強中に遭遇した問題(4)
前回の「Ruby on Railsを勉強中に遭遇した問題(3)」の続きになります。
テキストとして使用している「Ruby on Rails 6 超入門」の、第5章「その他に覚えておきたい機能」の「Reactとの連携」以降で遭遇したものです。
ただ、「Reactとの連携」については Rails 7 で大きく変わっているため、テキストと同じようなことを別の方法で試しています。
- 価格: 3520 円
- 楽天で詳細を見る
テキストに従ってやっていくと、テキストには書かれていない問題にいろいろ遭遇しました。
ここでは、遭遇した問題について、内容と対応を記録したいと思います。
Reactとの連携
Yahoo!ニュース・ヘッドラインを表示しよう!
REXML::ParseException
テキストと同じように、ajaxアクションメソッドをコーディングしたところ、いきなり以下のエラーが出ました。
「Missing end tag for 'link'」で Webをググッても、ピッタリのものはヒットしません。
ただ、url が関係することもあるという事なので、url 'https://news.yahoo.co.jp/pickup/rss.xml' を実際にブラウザーで確認してみると、存在していませんでした。
どうやら、url が変更になったようです。
yahoo の rss は以下のページにまとまっていました。
その中の、「主要 - トピックス」にアクセスしてみると、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 を勉強していく中で、いろいろ経験することができました。
切りがいいので、続きは別のページに載せていきたいと思います。