Ruby on Rails - настройка функций отзывов
Я пытаюсь настроить функцию в своем приложении Ruby on Rails, которая позволяет пользователям просматривать фотографии.
Я следовал этому руководству в качестве ссылки.
http://ruby.about.com/od/rubyonrails/ss/blogpart4_4.htm
Исходя из моего опыта работы над другими проектами Ruby on Rails, я думаю, что модель отношений Posts/Comments может быть использована здесь для отношений Pictures/Reviews.
Я сначала создал эшафот.
rails g scaffold review name:string body:text picture:references
Мне бы хотелось, чтобы на каждой странице с картинками была отдельная страница для собственных обзоров.
Так как мне не нужна страница индекса для моего контроллера обзоров, я удалил эту строку из моего файла rout.rb
resources: reviews
Я заменил это, создав маршруты
match '/pictures/:id/reviews', to: 'reviews#show', via: 'get'
match '/pictures/:id/reviews/edit', to: 'reviews#edit', via: 'get'
match '/pictures/:id/reviews/new', to: 'reviews#new', via: 'get'
Здесь мой путь включает в себя вложенные обзоры внутри картинок.
маршрут
favorite_picture_path PUT /pictures/:id/favorite(.:format) pictures#favorite
pictures_path GET /pictures(.:format) pictures#index
POST /pictures(.:format) pictures#create
new_picture_path GET /pictures/new(.:format) pictures#new
edit_picture_path GET /pictures/:id/edit(.:format) pictures#edit
picture_path GET /pictures/:id(.:format) pictures#show
PATCH /pictures/:id(.:format) pictures#update
PUT /pictures/:id(.:format) pictures#update
DELETE /pictures/:id(.:format) pictures#destroy
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions_path POST /sessions(.:format) sessions#create
new_session_path GET /sessions/new(.:format) sessions#new
session_path DELETE /sessions/:id(.:format) sessions#destroy
contacts_path POST /contacts(.:format) contacts#create
new_contact_path GET /contacts/new(.:format) contacts#new
root_path GET / pictures#welcome
users_new_path GET /users/new(.:format) users#new
about_path GET /about(.:format) pictures#about
GET /contacts(.:format) contacts#new
GET /users/:id/favorites(.:format) users#favorites
signup_path GET /signup(.:format) users#new
signin_path GET /signin(.:format) sessions#new
signout_path DELETE /signout(.:format) sessions#destroy
GET /pictures/:id/reviews(.:format) reviews#show
GET /pictures/:id/reviews/edit(.:format) reviews#edit
GET /pictures/:id/reviews/new(.:format) reviews#new
updated_path GET /updated(.:format) pictures#newest_updates
GET /top-rated(.:format) pictures#high_ratings
ReviewsController
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
def show
@picture = Picture.find(params[:id])
@review = Review.find(params[:id])
end
def new
@review = Review.new
end
def edit
@picture = Picture.find(params[:picture_id])
@review = Review.find(params[:id])
end
def create
@picture = Picture.find(params[:picture_id])
@review = @picture.reviews.build(params[:review])
if @review.save
;flash[:notice] = 'Review was successfully created.'
redirect_to @picture
else
flash[:notice] = "Error creating review: #{@review.errors}"
redirect_to @picture
end
end
def update
@picture = Picture.find(params[:picture_id])
@review = Review.find(params[:id])
if @review.update_attributes(params[:review])
flash[:notice] = "Review updated"
redirect_to @picture
else
flash[:error] = "There was an error updating your review"
redirect_to @picture
end
end
def destroy
@picture = Picture.find(params[:picture_id])
@review = Review.find(params[:id])
@review.destroy
redirect_to(@review.post)
end
private
def set_review
@review = Review.find(params[:id])
end
def review_params
params.require(:review).permit(:username, :body, :picture_id)
end
end
Я удалил действие index из моего ReviewsController.
модели
class Review < ActiveRecord::Base
belongs_to :picture
end
class Picture < ActiveRecord::Base
has_many :reviews
end
Выше я установил отношения один-ко-многим между фотографиями и рецензиями.
Отзывы Миграция
class CreateReviews < ActiveRecord::Migration
def change
create_table :reviews do |t|
t.string :username
t.text :body
t.references :picture, index: true
t.timestamps
end
end
end
Исходя из моего понимания Rails, это должно работать.
Картинки # Показать страницу
<% @title = "#{@picture.title}" %>
<h4 class = 'indent'>Picture Statistics</h4>
<ul id = 'view'>
<li><strong>Title:</strong> <%= @picture.title %></li>
<li><strong>Category:</strong> <%= @picture.category %></li>
<li><strong>Rating:</strong> <%= pluralize(@picture.rating, 'Star') %></li>
<li><strong>Favorited:</strong> By <%= pluralize(@picture.users.count, 'User') %></li></br>
</ul>
<% if @picture.rating > 4 %>
<button class = 'top-picture'>Top Rated</button>
<% end %>
<%= form_for @picture do |f| %>
<p>
<%= f.label :stars, 'Rating', class: 'indent' %>
<div class= "rating">
1 ☆<%= f.radio_button :stars, '1' %>
2 ☆<%= f.radio_button :stars, '2' %>
3 ☆<%= f.radio_button :stars, '3' %>
4 ☆<%= f.radio_button :stars, '4' %>
5 ☆<%= f.radio_button :stars, '5' %>
</div>
</p>
<p class = 'indent'>
<input class="btn btn-info" type="submit" value="Review">
</p>
<a href = "/pictures/:id/reviews">Reviews</a>
<% end %>
<p class = 'indent'>
<a class="btn btn-info" href="/pictures" role="button">Index</a>
</p>
Однако, когда я нажимаю на ссылку в моем Pictures/:id(показать страницу)
<a href = "/pictures/:id/reviews">Reviews</a>
Ошибка RecordNotFound
Active Record::RecordNotFound in ReviewsController#show
Couldn't find Review with id=:id
Extracted source (around line #54):
53 def set_review
54 @review = Review.find(params[:id])
55 end
56
57 def review_params
Так как я столкнулся с ошибкой RecordNotFound, я подозреваю, что проблема лежит в ReviewsController, скорее всего, с параметрами.
Я верю, что у меня правильная идея, но я где-то допустил ошибку. Обратная связь и критика очень ценятся. Извините, если это звучит как глупый вопрос, я просто не очень хорош в Ruby.
4 ответа
Маршруты
Ради потомков вам лучше всего настроить маршруты следующим образом:
#config/routes.rb
resources :pictures do
resources :reviews, only: [:show, :edit, :new]
end
Всякий раз, когда вы создаете маршруты в Rails, вы должны помнить, что вся структура была построена вокруг "объектов" / "ресурсов". Вот почему маршруты известны как resourceful
маршруты (и почему у них есть resources
директива) - они позволяют вам определять маршруты вокруг различных ресурсов вашего приложения
Я рекомендую использовать nested
структура ресурсов.
-
Помощники
Ваша проблема была решена с использованием кода, предоставленного Santosh
и тому подобное. IE:
<%= link_to "Your Link", your_link_path(@object) %>
Вы должны оценить, как это работает. Каждый раз, когда вы используете route
помощник в Rails (в link_to
помощник), он будет просматривать ваши маршруты и найти детали, которые ему нужны.
Вы ссылались на следующий путь: pictures/:id/reviews
- как выяснилось, это неправильно, потому что Rails не имеет никакого отношения к URL ссылки, кроме ее построения во время рендеринга.
Учитывая, что Rails - это основанная на HTTP инфраструктура без сохранения состояния, Rails должен сопоставлять любые данные при каждом запросе. Это означает, что если вы хотите создавать ссылки, вы должны позволить Rails создавать ссылки при рендеринге, передавая статический набор данных вашему контроллеру в серверной части.
Надеюсь, это поможет?
Как у вас .html.erb
файл, старайтесь не писать сырой HTML.
Просто обновите эту ссылку:
<a href = "/pictures/:id/reviews">Reviews</a>
к
<%= link_to "Reviews", picture_reviews_path(@picture) %>
Редактировать:
Вы должны присвоить имена своим match
заявления как:
match '/pictures/:id/reviews', to: 'reviews#show', via: 'get', :as => 'picture_reviews'
Это сгенерирует:
picture_reviews GET /pictures/:id/reviews(.:format) reviews#show
match '/pictures/:id/reviews', to: 'reviews#show', via: 'get'
match '/pictures/:id/reviews/edit', to: 'reviews#edit', via: 'get'
Эти 2 маршрута не имеют идентификатора проверки, но ваш контроллер ожидает их. внести это изменение
match '/pictures/:picture_id/reviews/:id', to: 'reviews#show', via: 'get'
match '/pictures/:picture_id/reviews/:id/edit', to: 'reviews#edit', via: 'get'
И изменить это
<a href = "/pictures/:id/reviews">Reviews</a>
в
<a href = "/pictures/#{@picture.id}/reviews/#{@review.id}">Reviews</a>
Но вы должны серьезно рассмотреть вопрос об использовании ресурсов ресурсов и помощников
Попробуйте использовать вложенные ресурсы, а не создавать их вручную
resources :pictures, except: [:index] do
resources :reviews
end
И как уже упоминалось, вы должны использовать rails link_to для генерации правильных URL