- 投稿日:2020-01-24T20:45:29+09:00
Rails Javascript/Html: 投稿編集画面で写真の表示を確認したい!
= f.file_field :image, id: :message_img, placeholder: "写真の貼り付け:" 以下にJavaScriptを配置
:javascript $(function() { function readURL(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function (e) { $('#img_prev').attr('src', e.target.result); } reader.readAsDataURL(input.files[0]); } } $("#message_img").change(function(){ readURL(this); }); });・img_prevの属性操作
・changeメソッドでmessage_imgの読み込みURLを変更する.field__img-show
= image_tag @message.image.url, id: :img_prev,size: '800x600' if @message.image?最後にimage_tagで変更されたimg_prevを表示。
つぎはぎの知識でなんとか起動させることができました^^;
- 投稿日:2020-01-24T20:26:15+09:00
Railsの思想
はじめに
「パーフェクト Ruby on Rails」に Rails の特徴、強く打ち出している思想について始めのほうに記載されていたので「パーフェクト Ruby on Rails」を振り返り、メリットを知りたいと思いましたのでまとめます。
CoC(Convention over Configuration)
直訳では「設定より規約」になります。有名です。
従来のアプリケーションフレームワークには規約がなく、開発者が自由に設定ができますが、Railsはファイル名の規約やテーブル定義の規約など様々な規約があります。パーフェクト Ruby on Railsの例(そのままではないです)
- 社員情報を表現するモデルをEmployeeモデルとした場合、Railsで規約には則って開発することが求められる
- データベースのテーブル名はモデル名の複数形のEmployeesにする
- /employeesというURLは社員の一覧を表す
- /employees/1というURLは社員ID:1の社員情報を表す
✔️メリット
- 規約に則って記述することで、設定のファイルを書く必要がない
- プロジェクトごとに設定の差異を生んでしまうことがない
- 共通のルールなので、他のエンジニアとコミュニケーションが取りやすい
- 開発者が決定すべきことが減る
DRY(Don’t Repeat Yourself)
「繰り返してはいけない」「同じことは繰り返さない」と訳されます。
同じソースコードを統一し短くコードを書く事を推奨する思想があります。
情報の重複をなくし、1つのことは1箇所に記述します。✔️メリット
- DRY原則を守ることにより、コードを変更する際に何箇所も変更する必要がなくなる
REST(REpresentational State Transfer)
Webのアプリケーション設計思想のひとつです。
RESTfulという言葉をよく目にしますが、RESTという設計思想に則ったアーキテクチャのことをいいます。パーフェクト Ruby on Railsの例(そのままではないです)
- /employees/1というURIが指す内容が「リソース」とすると
- /employees/1にHTTPのGETメソッドでアクセスすることで、社員情報を取得する処理を行える
- /employees/1にHTTPのDELETEメソッドでアクセスすることで、社員情報を削除する処理を行える
✔️メリット
- アプリケーション中のリソースがURIによって参照できる
- 機能追加がしやすい自然な設計になる
- CRUD操作と、4つの基本的なHTTPrequestメソッド(GET,POST,PUT,DELETE)の両方に対応している
おしまい
「パーフェクト Ruby on Rails」を進められ最近読み始めました。話題がたくさんで読み応えがあると聞いたので、読み進めて知識を増やしたいですね〜!頑張ります。
ちょっとだけRails tutorialも参考にいたしました。
- 投稿日:2020-01-24T19:30:20+09:00
Action Cableの設定でつまずいたこと
行っていること
以下の記事や動画を参考にチャット機能を作成しています。
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
0から手を動かして作るRailsチャットアプリ【チュートリアル】リアルタイムでのチャット機能を作成する際につまずいたことを、記録も兼ねて共有します。
やりたいこと
チャンネルの作成
$ rails g channel chatroom speak create app/channels/chatroom_channel.rb create app/assets/javascripts/channels/chatroom.coffeeつまずいたこと
・
chatroom_channel.rb
から_post.html.erb
をrenderで呼び出そうとすると、[ActionView::Template::Error - undefined method 'id' for nil:NilClass]
と言われる。→channelからrenderした際にcurrent_user
の値を取れていないためコード一覧
routes.rbRails.application.routes.draw do root to: 'toppages#index' # (省略) resources :chatrooms do member do get :users end end mount ActionCable.server => '/cable' endposts/_post.html.erb<% unless post.user_id == current_user.id %> <p style="color:blue;"><%= post.content %></p> <% else %> <p style="color:red;"><%= post.content %></p> <% end %>chatroom_channel.rbclass ChatroomChannel < ApplicationCable::Channel def subscribed stream_from "chatroom_channel" end def unsubscribed # Any cleanup needed when channel is unsubscribed end def speak(data) message = Post.create! content: data['message'], user_id: data['user_id'], chatroom_id: data['room_id'] templete = ApplicationController.renderer.render(partial: 'posts/post', locals: { post: message }) ActionCable.server.broadcast 'chatroom_channel', message: templete end endchatroom.coffee# クライアントサイドの処理を受け持つチャンネ App.chatroom = App.cable.subscriptions.create "ChatroomChannel", connected: -> # Called when the subscription is ready for use on the server disconnected: -> # Called when the subscription has been terminated by the server received: (data) -> $('#posts').append data['message'] # Called when there's incoming data on the websocket for this channel speak: (content, data_user, data_room) -> @perform 'speak', message: content, user_id: data_user, room_id: data_room document.addEventListener 'DOMContentLoaded', -> input = document.getElementById('chat_input') data_user = input.getAttribute("data_user") data_room = input.getAttribute("data_room") button = document.getElementById('chat_button') button.addEventListener 'click', -> content = input.value App.chatroom.speak(content, data_user, data_room) input.value = '' return return原因
channelからは sessionを使うことが出来ないそうです。
(sessions_helperでcurrent_userを定義している。)解決方法
channelからcookieは使うことができるそうなので、cookieからユーザー情報を取ってきて、current_user変数に代入。
主にこちらの記事を参考にしました。cookieの情報からcurrent_userの作成
channels/application_cable/connection.rbmodule ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect self.current_user = find_verified_user end protected def find_verified_user if verified_user = User.find_by(id: session['user_id']) verified_user else reject_unauthorized_connection end end def session cookies.encrypted[Rails.application.config.session_options[:key]] end end endchatroom_channel.rb# (省略) def speak(data) message = Post.create! content: data['message'], user_id: data['user_id'], chatroom_id: data['room_id'] templete = ApplicationController.renderer.render(partial: 'posts/post', locals: { post: message, current_user: current_user }) # current_user変数にconnection.rbで取得したcurrent_userを設定 ActionCable.server.broadcast 'chatroom_channel', message: templete end参考リンク
- 投稿日:2020-01-24T19:00:31+09:00
【Rails】掲示板に禁止ワードを設定する
掲示板にクローラー的なやつがリンクやスクリプトを書き込み始めたので、暫定的な対応をしました。
comments_controller.rbdef create #以下の4行で対応 prohibited_words = ['a href=', '<script'] if prohibited_words.any? { |p| comment_params[:content].include?(p) } redirect_to(comments_url) && return end @comment = Comment.new(comment_params) if @comment.save . .説明不要かもですが、まず
prohibited_words = ['a href=', '<script']
で禁止ワードを設定して、prohibited_words.any? { |p| <検証したい文字列>.include?(p) }
で検証したい文字列に禁止ワードが含まれているかをチェックしています。p.s.
掲示板荒らし対策に詳しい方、ご連絡ください。
- 投稿日:2020-01-24T16:29:18+09:00
リソースとは
- 投稿日:2020-01-24T16:13:56+09:00
Railsチュートリアル 第5章
ヘルパーメソッド
link_to
リンクを生成するためのヘルパーメソッド
<%= link_to "sample app", '#', id: "logo" %>第1引数:リンクテキスト
第2引数:URL
第3引数:オプションハッシュ(必須ではない)image_tag
画像を表示するためのimgタグを作成するヘルパーメソッド。
image_tag("rails.png", alt: "Rails logo")第1引数:画像ファイル名
ファイルの置き場所は「app/assets/images」フォルダと「public」フォルダの2つが用意されている。
上記の様に指定すると、「app/assets/images」が参照される。
「public」フォルダを参照したい場合は、ファイル名の前に「/」を入れる。
第2引数:オプション
alt:画像がない場合に代わりに表示される文字列
size:'100×200' 幅と高さを指定<%= link_to image_tag("rails.png", alt: "Rails logo"), 'http://rubyonrails.org/' %>上記の様に組み合わせて使うことができ、画像リンクが作れる
第1引数:image_tag("rails.png", alt: "Rails logo") ⇨画像
第2引数:'http://rubyonrails.org/' ⇨URLBootstrap
Bootstrapとは
Twitter社が開発したCSSのフレームワークです。(HTML/CSS/JavaScriptから構成される)
よく使うスタイルなどがあらかじめ定義されている。
また、レスポンシブWebデザインに対応しているので、スマートフォンやタブレットなど個別に対応するスタイルを作らなくても柔軟に調整してくれる。BootstrapではLESS CSS言語を使っているが、RailsのAsset PipelineはデフォルではSass言語をサポートしているので、bootstrap-sassは、LESSをSassへ変換し、Bootstrapファイルを現在のアプリケーションで全て利用できるようにする。
Sass
CSSを拡張した言語、元々のCSSに次の機能を追加
・ネスト
スタイルシート内に共通のパターンがある場合、要素をネストさせることができる
・変数
冗長なコードを削除し、より自由な表現を可能に
・ミックスイン
CSSルールのパッケージ化して、複数の箇所で再利用することができる (例:@include)Bootstrap導入
Gemfile.rbsource 'https://rubygems.org' gem 'rails', '5.1.6' gem 'bootstrap-sass', '3.3.7' ⇦追加 . .Bootstrapをインストール
$ bundle installカスタムCSSを作成
$ touch app/assets/stylesheets/custom.scsscustome.scss@import "bootstrap-sprockets"; @import "bootstrap";パーシャル
一箇所にまとめた方が良いHTMLや重複しているHTMLをパーシャルという機能を使って1つにまとめることができる。
パーシャルのファイル名の先頭にはアンダースコアをつける。
またrenderメソッドで使用する。アセットパイプライン
CSS/JavaScript/Imageなどを管理する機能
アセットディレクトリ
静的ファイルを目的別に分類
- app/assets:現在のアプリケーション固有のアセット
- lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット
- vendor/assets: サードパーティのアセット
マニフェストファイル
1つのファイルにまとめる方法をRailsに指示
app/assets/stylesheets/application.css/* * This is a manifest file that'll be compiled into application.css, which * will include all the files listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, * vendor/assets/stylesheets, or vendor/assets/stylesheets of plugins, if any, * can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear * at the bottom of the compiled file so the styles you add here take * precedence over styles defined in any styles defined in the other CSS/SCSS * files in this directory. It is generally better to create a new file per * style scope. * *= require_tree . *= require_self */require_tree:app/assets/stylesheetsディレクトリ内の全てのCSSファイルがアプリケーションCSSに含まれるようにしている。
require_self:CSSの読み込みシーケンスの中で、application.css自身もその対象に含めている。プリプロセッサエンジン
指示に従ってブラウザに配信できるように結合
なぜアセットパイプライン?
開発する側としては複数のファイルに分割して効率的に開発できる
ただ、コンピューターに取っては1つにまとまっていた方が高速になるので、それをしてくれるのがアセットパイプライン名前付きルート
このようなルートは
get 'static_pages/help'このように変更する
get '/help', to: 'static_pages#help'GETリクエストが/helpに送信されたときにStaticPagesコントローラーのhelpアクションを呼び出してくれるようになる。
また、ルートURLの時と同様に、help_pathやhelp_urlといった名前付きルートも使えるようになる。asオプション
:asオプションを使うと、ルーティングの名前を指定できる。
get '/help', to: 'static_pages#help', as: :helfhelf_pathとして使用できる
リンクのテスト
require 'test_helper' class SiteLayoutTest < ActionDispatch::IntegrationTest test "layout links" do get root_path ⇨ルートURL(Homeページ)にGETリクエストを送る assert_template 'static_pages/home' ⇨正しいテンプレートが表示されている事を確認 assert_select "a[href=?]", root_path, count: 2 ⇨Homeページへのリンクが2つ存在する事を確認 assert_select "a[href=?]", help_path ⇨Helpページへのリンクが存在する事を確認 assert_select "a[href=?]", about_path ⇨Aboutページへのリンクが存在する事を確認 assert_select "a[href=?]", contact_path ⇨Contactページへのリンクが存在する事を確認 end endassert_selectにはいくつもの指定の方法があるが、今回はリンクのテストをする。
コード マッチするHTML assert_select "div" <div>foobar</div> assert_select "div", "foobar" <div>foobar</div> assert_select "div.nav" <div class="nav">foobar</div> assert_select "div#profile" <div id="profile">foobar</div> assert_select "div[name=yo]" <div name="yo">hey</div> assert_select "a[href=?]", ’/’, count: 1 <a href="/">foo</a> assert_select "a[href=?]", ’/’, text: "foo" <a href="/">foo</a>
- 投稿日:2020-01-24T14:54:09+09:00
Railsのテンプレファイル(html.erb)でのコメント方法
一度うまくいった記述を、きれいなコードにする際にコメントアウトして残す癖があるが、html.erbファイルでのコメント方法が分からず調べたため備忘録として。
<%#= %>
もしくは<%# %>
で囲む<%# ココはコメントアウトされる %> <%#= ココはコメントアウトされる %>複数行の場合は
<%# ココは コメントアウト される %>
2.<% if false %>
<% end %>
で囲む
できるっちゃできますが、コメントアウトというより正しくはデッドロジック作っているので、やはり無理やり感ありますね。<% if false %> ココはコメントアウトされる <% end %>その他
なお、他にも、複数行コメントとして、
<% begin %>
と<% end >%
で囲むという方法も見つかりましたが、上記1.ほどシンプルでなく改行によってはうまく機能しなかったりするので、通常使うにはイマイチということで、記載していません。参考
- 投稿日:2020-01-24T14:35:47+09:00
あっさり読むrails 番外(image)
はじめに
以前の記事の応用で、画像アドレスをフォームに入力すると、自動的に画像が表示されるようにします。
前提
前記事をそのまま修正します。
実行
ビューファイルを次の様に修正します。
sample.haml.html= form_with model:@sample, local: true do |f| = f.text_area :name, placeholder: "サンプル", class: "sample-form" .add-image
add-text
をadd-image
に変えただけです。JSファイルを次の様に書きます。
sample.js$(function(){ $(".sample-form").on("change" functon(){ var image = $(this).val(); let html = ` <div class = "add-image__sample"> <img src = "$(image)" height = "500" //heightはなんでもいい </div> ` ; $(".add-image").append(html); }) });大雑把な流れとしては、
1.フォーム(.sample-form)の中身が変わった("change")時=画像アドレスを貼り付けた時
2.その値をimageに代入し
3.それを表示させるhtmlデータを変数に代入し
4..add-imageに追加(append)する
となります。
本当は、別の画像アドレスを貼り付ける時に元の画像を削除する必要がありますが、
ひとまずはこれで非同期の画像表示ができます。
- 投稿日:2020-01-24T13:50:52+09:00
メモ:ActionMailerのログにメールアドレスが出ないようにする
この記事は
- 意外とぱっとできなかったので個人メモです
やりたかった事
- ActionMailerでメールを送信する際に、下記のようにログにメールアドレスが出てしまうのですが、セキュリティのレギュレーション上、これを止めたかったです
INFO -- : [ActiveJob] [ActionMailer::DeliveryJob] Sent mail to test@example.com (95.4ms)やり方
- Rails側で設定はできません
- モンキーパッチあてればいい説があり、やってみたのですが、これが全く反映されない
- 結局、下記のようにLogSubscriberのサブクラスを作って、ActionMailerが読み込まれたあとでattachしなおしたら反映されました
config/initializers/log_subscriber_ext.rbActiveSupport.on_load(:action_mailer) do class LogSubscriberExt < ActionMailer::LogSubscriber def deliver(event) info do recipients = Array(event.payload[:to]).join(", ") "Sent mail to [FILTERED] (#{event.duration.round(1)}ms)" end debug { event.payload[:mail] } end end LogSubscriberExt.attach_to :action_mailer end
- ちなみにメソッドの中身は
/actionmailer-5.2.0/lib/action_mailer/log_subscriber.rb
をコピーしてFILTER文字列で潰しただけです- Railsのバージョンによって中身が異なるかもしれないので注意
終わりに
- Web側はfilter_parameter_loggingみたいな仕組みがあるんだから、こっちにも準備して欲しいなー
参考
- blousonのこのコードが非常に役に立ちました
- 投稿日:2020-01-24T12:12:31+09:00
rails install で詰まった話
結論この記事を参考にしたら解決
https://qiita.com/amuyikam/items/313bc89c1de320a4257e
こんなエラーが
➜ ~ gem install rails ERROR: Error installing rails: zeitwerk requires Ruby version >= 2.4.4.rubyのバージョンが古かった。
➜ ~ ruby -v ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin18]この記事を参考にrubyのバージョンを 2.4以上にする
https://qiita.com/TAByasu/items/47c6cfbeeafad39eda07
ダメか
➜ ~ rails new sample Rails is not currently installed on this system. To get the latest version, simply type: $ sudo gem install rails You can then rerun your "rails" command.# これで解決 hash -r➜ ~ rails _5.2.2.1_ new sample
- 投稿日:2020-01-24T02:17:55+09:00
ミニQ & Aサービスの開発
Udemyの教材でミニQ&Aサービスの開発について学んだので、備忘録として記録します。
教材:https://www.udemy.com/course/the-ultimate-ruby-on-rails-bootcamp/Rubyのバージョン管理
今回はバージョン2.5.1で進めました。
ターミナル$ rvm -v #rvmのバージョンを調べる $ rvm 1.29.8 (1.29.8) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io] $ rvm list =* ruby-2.5.1 [ x86_64 ] ruby-2.6.3 [ x86_64 ] # => - current # =* - current && default # * - default $ rvm install 2.5.1 #バージョンを指定してインストールしたい場合 $ rvm use 2.5.1 #currentになる $ rvm --default use 2.5.1 #current && defaultになるRailsのインストール
バージョンを指定する場合の書き方。-Nはドキュメントをインストールしないという意味で時間短縮になる。
ターミナル$ gem install rails -v 5.2.1 -N
Bundler
RubyGemsを管理するツール
RubyGems
Rubyで書かれたサードパーティ製のライブラリ(プログラムのまとまり)
ex) ユーザー認証機能、画像の管理機能、管理画面の機能、など
http://rubygems.org/ミニQ and Aアプリ作成
ターミナル$ rails _5.2.1_ new qandaGemfile#エラー回避 #変更前 gem 'sqlite3' #変更後 gem 'sqlite3', '~> 1.3.6'ターミナル$ bundle updateデータベースを作成する
ターミナルrails db:create
Bootstrapの導入
Gemfilegem 'bootstrap', '~> 4.1.1' gem 'jquery-rails', '~> 4.3.1' #bootstrapはjQueryに依存しているターミナル$ bundle installstylesheetのファイル形式変更(CSS→Sass)
ターミナル$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scssapplication.scss@import "bootstrap";application.js// This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's // vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. JavaScript code in this file should be added after the last require_* statement. // // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // //= require rails-ujs //= require activestorage //= require turbolinks //= require jquery3 #ここを追記 //= require popper #ここを追記 //= require bootstrap-sprockets #ここを追記 //= require_tree .route
ルーティングの設定
ターミナル$ rails routes Prefix Verb URI Pattern Controller#Action root GET / questions#index question_answers GET /questions/:question_id/answers(.:format) answers#index POST /questions/:question_id/answers(.:format) answers#create new_question_answer GET /questions/:question_id/answers/new(.:format) answers#new edit_question_answer GET /questions/:question_id/answers/:id/edit(.:format) answers#edit question_answer GET /questions/:question_id/answers/:id(.:format) answers#show PATCH /questions/:question_id/answers/:id(.:format) answers#update PUT /questions/:question_id/answers/:id(.:format) answers#update DELETE /questions/:question_id/answers/:id(.:format) answers#destroy questions GET /questions(.:format) questions#index POST /questions(.:format) questions#create new_question GET /questions/new(.:format) questions#new edit_question GET /questions/:id/edit(.:format) questions#edit question GET /questions/:id(.:format) questions#show PATCH /questions/:id(.:format) questions#update PUT /questions/:id(.:format) questions#update DELETE /questions/:id(.:format) questions#destroy rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#createconfig/routes.rbRails.application.routes.draw do root 'questions#index' #indexアクションのビューをrootに設定されるようする resources :questions do #questionsコントローラーに関係するルーティングを自動で用意してくれる resources :answers end endmodel
Questionモデルの作成
ターミナル$ rails g model Question name:string title:string content:text $ rails db:migrateAnswerモデルの作成
ターミナル$ rails g model Answer question:references name:string content:text #question:references→1対多の関係を定義出来る $ rails db:migrateデータベース構造の確認
ターミナル$ rails dbconsole SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .schema #.schemaと入力 CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY); CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL); CREATE TABLE "questions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "title" varchar, "content" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL); CREATE TABLE "answers" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "question_id" integer, "name" varchar, "content" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL, CONSTRAINT "fk_rails_3d5ed4418f" FOREIGN KEY ("question_id") REFERENCES "questions" ("id") ); CREATE INDEX "index_answers_on_question_id" ON "answers" ("question_id"); sqlite> .q #.qと入力question.rbclass Question < ApplicationRecord has_many :answers, dependent: :destroy #questionは複数のanswerを持っているという意味 #dependent: :destroy→親のquestionが削除されたら、それに紐づくanswersも全て削除される validates :name, presence: true #データが未入力の時に保存しないようにする validates :title, presence: true validates :content, presence: true endanswer.rbclass Answer < ApplicationRecord belongs_to :question #answerはquestionによって所有されていると言う関係 validates :content, presence: true validates :name, presence: true endcontroller
ターミナル$ rails g controller questions index show new edit #questionsコントローラーのindex,show,new,editアクションを作成question_controller.rbclass QuestionsController < ApplicationController #コントローラーの各アクションが実行される前にset_questionを実行する before_action :set_question, only: [:show, :edit, :update, :destroy] #一覧を表示する def index #Questionの全データの配列を取得して、@questionsインスタンス変数へ代入する @questions = Question.all end #詳細を表示する def show # @question = Question.find(params[:id]) #リファクタリング @answer = Answer.new #Answerクラスのインスタンスを作り、@answerインスタンス変数へ代入 end #新規作成 def new @question = Question.new #Questionモデルの空のインスタンスを作り、@questionインスタンス変数へ代入 end #保存 def create @question = Question.new(question_params) #name, title, contentを@questionに代入 if @question.save #保存されたら redirect_to root_path, notice: 'Success!' #「Success!」と表示してルートパスにリダイレクトする else #保存できない場合は flash[:alert] = "Save error!" #「Save error!」と表示して render :new #新規ページに戻る end end #編集 def edit # @question = Question.find(params[:id]) #リファクタリング end #アップデート def update # @question = Question.find(params[:id]) #リファクタリング if @question.update(question_params) #name, title, contentをアップデートできたら redirect_to root_path, notice: 'Success!' #「Success!」と表示してルートパスにリダイレクトする else #アップデートできない場合は flash[:alert] = "Save error!" #「Save error!」と表示して render :edit #編集ページに戻る end end def destroy # @question = Question.find(params[:id]) #リファクタリング @question.destroy #削除する redirect_to root_path, notice: 'Success!' #「Success!」と表示してルートパスにリダイレクトする end private def set_question #@question = Question.find(params[:id])が重複しているので共通化する! @question = Question.find(params[:id]) #(params[:id])を取得して@questionに代入 end #ストロングパラメーター private #クラスの内部だけで使用する def question_params params.require(:question).permit(:name, :title, :content) #name,title,contentのみの値を@questionに渡す end end★paramsに入るデータをデバッグツールbyebugで確認する
formに値を入れて、ターミナルでparamsを入力するとフォームから送られてきた値を確認することができる
終了するには、quitを実行するquestion_controller.rbprivate def question_params byebug #byebugを入力 params.require(:question).permit(:name, :title, :content) #paramsにはフォームから送られてきたデータが入る endターミナル$ rails g controller answers edit #answersコントローラーのeditアクションを作成answers_controller.rbclass AnswersController < ApplicationController #保存 def create #question_idを元にデータベースから該当のquestionを取得して変数に代入する @question = Question.find(params[:question_id]) #Answerモデルの空のインスタンスを作り、@answerインスタンス変数へ代入 @answer = Answer.new #content,name,question_idを保存できたら if @answer.update(answer_params) #「Success!」と表示して詳細ページににリダイレクトする redirect_to question_path(@question), notice: 'Success!' #アップデートできない場合は else #「Invalid!」と表示して詳細ページににリダイレクトする redirect_to question_path(@question), alert: 'Invalid!' end end def edit #question_idを元にデータベースから該当のquestionを取得して変数に代入する @question = Question.find(params[:question_id]) #取得した@questionから編集したいanswerのidを取得して@answerに代入する @answer = @question.answers.find(params[:id]) end def update #question_idを元にデータベースから該当のquestionを取得して変数に代入する @question = Question.find(params[:question_id]) #取得した@questionからアップデートしたいanswerのidを取得して@answerに代入する @answer = @question.answers.find(params[:id]) #アップデートできたら if @answer.update(answer_params) #「Success!」と表示して詳細ページににリダイレクトする redirect_to question_path(@question), notice: 'Success!' #アップデートできない場合は else #「Invalid!」と表示して flash[:alert] = 'Invalid!' #編集ページに戻る render :edit end end def destroy #question_idを元にデータベースから該当のquestionを取得して変数に代入する @question = Question.find(params[:question_id]) #取得した@questionから編集したいanswerのidを取得して@answerに代入する @answer = @question.answers.find(params[:id]) #削除する @answer.destroy #「Deleted!」と表示して詳細ページににリダイレクトする redirect_to question_path(@question), notice: 'Deleted!' end #ストロングパラメーター private def answer_params #content,name,question_idのみの値を@answerに渡す params.require(:answer).permit(:content, :name, :question_id) end endview
questions/application.html.erb<!DOCTYPE html> <html> <head> <title>Qanda</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <div class="container"> <% if flash[:notice] %> <p class="text-success"><%= flash[:notice] %></p> <% end %> <% if flash[:alert] %> <p class="text-danger"><%= flash[:alert] %></p> <% end %> <%= yield %> </div> </body> </html>質問一覧ページの作成
questions/index.html.erb<h2>Questions</h2> <div class="row"> <div class="col-md-12"> <table class="table table-striped"> <thead class="thead-light"> <tr> <th>ID</th> <th>Title</th> <th>Menu</th> </tr> </thead> <tbody> <% @questions.each do |question| %> <tr> <td><%= question.id %></td> <!-- 質問詳細画面へのリンク --> <!-- prefixに_pathをつけている --> <!-- (question)→:idとして読み込まれる --> <!-- question GET /questions/:id(.:format) questions#show --> <td><%= link_to question.title, question_path(question) %></td> <!-- edit_question GET /questions/:id/edit(.:format) questions#edit --> <td>[<%= link_to 'Edit', edit_question_path(question) %>] <!-- question DELETE /questions/:id(.:format) questions#destroy --> [<%= link_to 'Delete', question_path(question), method: :delete, data:{ confirm: 'Are you sure?' } %>]</td> </tr> <% end %> </tbody> </table> <div> <!-- new_question GET /questions/new(.:format) questions#new --> <%= link_to 'New question', new_question_path %> </div> </div> </div>シードファイルを使った初期データの投入
db/seeds.rbQuestion.create(id: 1, name: 'Test name 1', title: 'Test question 1', content: 'Test content 1') Question.create(id: 2, name: 'Test name 2', title: 'Test question 2', content: 'Test content 2') Question.create(id: 3, name: 'Test name 3', title: 'Test question 3', content: 'Test content 3')rails db:seed新規質問投稿ページの作成
questions/new.html.erb<div> <div class="col-md-4 offset-md-4"> <h2 class="text-center">New question</h2> <%= render 'form' %> <!--_form.html.erbを読み込む --> </div> </div>質問編集ページの作成
questions/edit.html.erb<div> <div class="col-md-4 offset-md-4"> <h2 class="text-center">Edit question</h2> <%= render 'form' %> <!--_form.html.erbを読み込む --> </div> </div>共通部分の作成
リファクタリング:プログラムを外部から見た時に動作を変えずに、ソースコードを整理すること
new.html.erbとedit.html.erbはほぼ同じ内容になっている
共通部分を_form.html.erbで作成し、new.html.erbとedit.html.erbで読み込むquestions/_form.html.erb<%= form_with model: @question, local: true do |f| %> <div class="form-group"> <label>Name</label> <%= f.text_field :name, class: "form-control" %> </div> <div class="form-group"> <label>Title</label> <%= f.text_field :title, class: "form-control" %> </div> <div class="form-group"> <label>Content</label> <%= f.text_area :content, class: "form-control" %> </div> <div class="text-center"> <%= f.submit "Save", class: "btn btn-primary" %> </div> <% end %>質問詳細ページの作成
questions/show.html.erb<div class="row"> <div class="col-md-12"> <h2><%= @question.title %></h2> <!-- 質問のタイトル --> <div> Content: <%= @question.content %> <!-- 質問の内容 --> </div> <div> Name: <%= @question.name %> <!-- 名前 --> </div> <hr> <div> <h3>Answers</h3> <table class="table table-striped"> <% if @question.answers.any? %> <!-- 質問の答えがある場合は下記を表示する --> <thead class="thead-light"> <tr> <td>Answer</td> <td>Name</td> <td>Menu</td> </tr> </thead> <tbody> <% @question.answers.each do |answer| %> <tr> <td> <%= answer.content %> <!-- 答えの内容 --> </td> <td> <%= answer.name %> <!-- 名前 --> </td> <td> <!-- edit_question_answer GET /questions/:question_id/answers/:id/edit(.:format)answers#edit --> [<%= link_to 'Edit', edit_question_answer_path(@question, answer) %>] <!-- question_answer DELETE /questions/:question_id/answers/:id(.:format) answers#destroy --> [<%= link_to 'Delete', question_answer_path(@question, answer), method: :delete, data: {confirm: 'Are you sure?'} %> ] </td> </tr> <% end %> </tbody> <% else %> <p>No answer yet.</p> <!-- 質問の答えがない場合に表示する --> <% end %> </table> </div> <h3>Post new answer</h3> <%= form_with model: [@question, @answer], local: true do |f| %> <%= f.hidden_field :question_id, { value: @question.id} %> <div class="form-group"> <label>Name</label> <%= f.text_field :name, class: 'form-control' %> </div> <div class="form-group"> <label>Content</label> <%= f.text_area :content, class: 'form-control' %> </div> <div class="text-center"> <%= f.submit "Post", class: 'btn btn-primary' %> </div> <% end %> <div> <%= link_to '> Home', root_path %> <!-- ルートパスに飛ぶ --> </div> </div> </div> <% end %>回答編集ページの作成
answers/edit.html.erb<div> <h2>Updates answer</h2> <%= form_with model:[@question, @answer], local: true do |f| %> <div class="form-group"> <div class="form-group"> <label>Name</label> <%= f.text_field :name, class: "form-control" %> </div> <div class="form-group"> <label>Content</label> <%= f.text_area :content, class: "form-control" %> </div> <div class="text-center"> <%= f.submit "Update", class: "btn btn-primary" %> </div> </div> <% end %> </div>
- 投稿日:2020-01-24T01:10:55+09:00
【解決策】formにカラムが設定されない!?
Webアプリを開発していて、routesとcontroller、viewを何度も見直したのにformを検証で見てみると何故かカラムが設定されない時に以下の方法で解決しました。
before
= form_with model: @message, url: job_messages_path(@job), local: true do |f| = f.text_field :textafter
= form_with model: @message, url: job_messages_path(@job), local: true do |f| = f.text_field :text, name: "message[text]"下の行に、name:"テーブル名[カラム名]"を書き足せばカラムが設定され、値を入れることができました!!
- 投稿日:2020-01-24T00:42:23+09:00
Active Storage + S3を使うときに気をつけること
備忘録なので無視してください
file_field
で写真をアップする時にdirect_upload
を設定しないとNo route matches
になる時がある。= f.file_field :image, direct_upload: true