質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

Q&A

解決済

1回答

1370閲覧

ActionTextで投稿した記事を検索し、テキストの部分だけ表示させたい。しかし何故か一回目の検索時にだけエラーが出てしまいます。

kema

総合スコア6

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

0グッド

0クリップ

投稿2020/10/27 02:47

編集2020/10/28 02:17

前提・実現したいこと

ActionTextを使用して投稿した記事の検索をして文章だけを一覧表示したい。
今回は検索の結果をBootstrapのCard機能をしようして一覧表示にしたいので、画像のデータがあるとレイアウトが崩れてしまいます。

発生している問題・エラーメッセージ

なんとかActionText内のデータを検索することには成功し、表示させることには成功したのですが,挙動が少しおかしいです。

エラーの発生条件

  • サーバーを再起動した後にトップ画面(URL:localhost:3000)を再読み込み後、検索フォームに何か文字を入力してから検索ボタンを押すと
Showing /Users/masakikengo/projects/tiisana/app/views/posts/search.html.erb where line #6 raised: undefined method `each' for :search:Symbol

とエラーが表示される。

  • ただ何も入力せずに検索ボタンだけを押してもエラーは出ずに画面遷移だけ行われ、その後に検索してもエラーは発生しない。

  • エラー発生後に同じ画面を再読み込みするとその後の検索では問題無く記事の内容は検索できるようになる。

  • ログイン状態はエラーの発生には関係がない。

検索結果を表示するactionのcode
app/controllers/posts_controller.erb

 def search @posts = Post.search(params[:keyword]) end

app/models/post.rb

class Post < ApplicationRecord ##省略## def self.search(search) if search != "" scope :search, -> (search_param = nil) { return if search_param.blank? joins("INNER JOIN action_text_rich_texts ON action_text_rich_texts.record_id = posts.id AND action_text_rich_texts.record_type = 'Post'") .where("action_text_rich_texts.body LIKE ? OR posts.title LIKE ? ", "%#{search_param}%", "%#{search_param}%") } else Post.all end end

なにぶん初心者なので細かい部分の動きの理解が乏しくて中々自分で調べているだけでは原因にたどり着けませんでした。

該当のソースコード

app/models/post.rb

class Post < ApplicationRecord has_rich_text :content has_one_attac hed :image belongs_to :user has_many :comments validates :title, presence: true, length: { minimum: 3 } validates :image, :content, presence: true validates :title, presence: true validates :content, presence: true def self.search(search) if search != "" scope :search, -> (search_param = nil) { return if search_param.blank? joins("INNER JOIN action_text_rich_texts ON action_text_rich_texts.record_id = posts.id AND action_text_rich_texts.record_type = 'Post'") .where("action_text_rich_texts.body LIKE ? OR posts.title LIKE ? ", "%#{search_param}%", "%#{search_param}%") } else Post.all end end end

app/controllers/posts_controller.erb

class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update, :destroy] before_action :move_to_index, except: [:index, :show, :search] def index @posts = Post.includes(:user).order("created_at DESC") end def show @post = Post.find(params[:id]) @comment = Comment.new @comments = @post.comments.includes(:user).order("created_at DESC") end def new @post = Post.new end def edit end def create @post = Post.new(post_params) respond_to do |format| if @post.save format.html { redirect_to @post, notice: 'Post was successfully created.' } format.json { render :show, status: :created, location: @post } else format.html { render :new } format.json { render json: @post.errors, status: :unprocessable_entity } end end end def update respond_to do |format| if @post.update(post_params) format.html { redirect_to @post, notice: 'Post was successfully updated.' } format.json { render :show, status: :ok, location: @post } else format.html { render :edit } format.json { render json: @post.errors, status: :unprocessable_entity } end end end def destroy @post.destroy respond_to do |format| format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' } format.json { head :no_content } end end def search @posts = Post.search(params[:keyword]) end private def set_post @post = Post.find(params[:id]) end def post_params params.require(:post).permit(:title, :content, :image).merge(user_id: current_user.id) end def move_to_index unless user_signed_in? redirect_to action: :index end end end

app/views/posts/search.html.rb

<div class="container" style="margin-top:100px;"> <div class="album py-5 bg-light"> <div class="container "> <div class="row"> <% @posts.each do |post| %> <div class="col-md-4"> <div class="card text-center"> <td><%= image_tag post.image.variant(resize:'200x200'), class: "card-img-top" %></td> <h4 class="card-text"><%= post.title %></h4> <div class="card-body"> <%= strip_tags(post.content.to_s).gsub(/[\n]/,"").strip.truncate(10)%> <div class="d-flex justify-content-between align-items-center"> <div class="btn-group mt-3 mx-auto"> <% if user_signed_in? && current_user.id == post. user_id%> <%= link_to '編集', edit_post_path(post), class: "btn btn-sm btn-outline-primary" %> <%= link_to '削除', post, method: :delete, data: { confirm: 'Are you sure?' } , class: "btn btn-sm btn-outline-primary"%> <% else %> <%= link_to '詳細', post, class: "btn btn-sm btn-outline-primary" %> <%= link_to 'トップページ', posts_path, class: "btn btn-sm btn-outline-primary" %> <% end %> </div> </div> <small class="text-muted mt-4"><%= post.created_at.to_s(:datetime_jp) %></small> </div> </div> </div> <% end %> </div> </div> </div> <div class="container" style="margin-bottom:100px;">

###追加のコード
app/views/layouts/application.html.erb

<body> <nav class="navbar navbar-light navbar-expand-md "> <a class="navbar-brand text-primary",class="h1" href="/"> <div class="h3">Tiisana</div> </a> <div class="collapse navbar-collapse"> <ul class="navbar-nav ml-auto"> <div class="navbar-item d-flex justify-content-end align-items-center"> <%= form_with(url: search_posts_path, local: true, method: :get, class: "search-form") do |form| %> <div class="input-group"> <%= form.text_field :keyword, class: "search-form navop" %> <%= button_tag sanitize('<i class="fa fa-search"></i>'), :type => "submit",:class =>"btn btn-light mr-1" %> </div> </div> <% end %> <% if user_signed_in? %> <li class="nav-item mr-2 "> <%= link_to "新規投稿", new_post_path, class: "nav-alink btn btn-light " %> </li> <li class="nav-item dropdown"> <div class="btn-group"> <button class="nav-alink btn btn-light dropdown-toggle" data-toggle="dropdown" href="/" aria-haspopup="true" aria-expanded="false"><%= current_user.nickname %> </button> <div class="dropdown-menu dropdown-menu-right"> <%= link_to "マイページ", "/users/#{current_user.id}", class: "dropdown-item", type:"button"%> <%= link_to "ログアウト", destroy_user_session_path, method: :delete, class:"dropdown-item", type:"button"%> </div> </div> <ul> </li> <% else %> <li class="nav-item mr-2"> <%= link_to "ログイン", new_user_session_path, class: "nav-alink btn btn-light" %> <%= link_to "新規登録", new_user_registration_path, class: "nav-alink btn btn-light"%> </li> </ul> <% end %> </div> </nav> <%= yield %> <nav class="navbar bg-light navbar-light navbar-expand-md mt-5 fixed-bottom"> <a class="navbar-brand text-center" href="/">© 2020 Tiisana</a> </nav> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script> </body>

試したこと

エラー分の内容的にeach文の中に渡している値がおかしいみたいのなので、ActionTextの内容を表示させる以下の部分を

<%= strip_tags(post.content.to_s).gsub(/[\n]/,"").strip.truncate(10)%>

以下に変更すると

<%= post.content %>

確かに投稿した内容は全て表示される。

検索機能と検索後に文章だけを抜粋するのは以下のサイトを参考に実装しました。

Rails6のActionTextでransackがうまく使えないので検索できるようにする
ActionText で truncate を使って文章を抜粋する

何度か記事を読み返して自分なりにコードをいじってみましたが解決できませんでした。

まだ質問に慣れていないので分かりにくい点も多いと思いますが、原因を教えていただけると非常に嬉しいです。

どうかよろしくおねがいします。

補足情報(FW/ツールのバージョンなど)

ruby_version 2.6.5

Rails 6.0.3.4

Bootstrap 4.1.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

winterboum

2020/10/27 21:17

posts/search.html.rb はどのactionから呼ばれますか? そのactionはどのviewから呼ばれますか
kema

2020/10/28 00:09

貴重な時間を頂き、ご返信ありがとうございます。 先に質問のposts/search.html.rbの拡張子の記述ミスだけ修正しました。 もう一度コードを見直したのですが、searchのactionはpostsコントローラーにあり、viewを呼ぶのはapplication.html.erbに記述している検索フォームから検索しています。 データの流れも考えてみましたがやはりエラーになるタイミングもまちまちで原因がいまいちわかりません。
winterboum

2020/10/28 01:06

application.html.erb (の少なくともbody部分) と エラーが額実に起きるケースをとりあえず一つで良いので  1.どのURLで検索した時か、 2.そのURLを表示するactionのcode を載せてください
kema

2020/10/28 02:18

修正いたしました。 引き続きよろしくお願いします!
guest

回答1

0

ベストアンサー

二回目以降にエラーにならない仕組みはわかりませんが、最初のエラーは
Post.search の中で scope を定義しています。この戻り値 :search がPost.searchの戻り値となっています。
def self.search(search) if search != "" scope :search, ->

scope はmethod定義の外で行ってください。
なお、scopeとmethodの名前を同じにするとあまりよろしくないです
if search != "";else;end も scopeに取り込んでしまっては?

scope :search, -> (search_param = nil) {  if search_param return if search_param.blank? joins("INNER JOIN action_text_rich_texts ON action_text_rich_texts.record_id = posts.id AND action_text_rich_texts.record_type = 'Post'") .where("action_text_rich_texts.body LIKE ? OR posts.title LIKE ? ", "%#{search_param}%", "%#{search_param}%") else all end }

投稿2020/10/28 03:57

編集2020/10/28 06:52
winterboum

総合スコア23401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kema

2020/10/28 07:54 編集

ありがとうございます!無事に解決致しました。 ご指摘にあったようにscope名をsearchtextに変更してみました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問