Ruby on Rails form error - ruby-on-rails

I am building an app from an online tutorial. It tracks "Movies" and "Rentals." I am trying to set up the part where you create a new rental. When I submit the form, I get this error:
ActiveModel::ForbiddenAttributesError in RentalsController#create
Here is the full rentals controller:
class RentalsController < ApplicationController
def new
#movie = Movie.find(params[:id])
#rental = #movie.rentals.build
end
def create
#movie = Movie.find(params[:id])
#rental = #movie.rentals.build(params[:rental])
if #rental.save
redirect_to new_rental_path(:id => #movie.id)
end
end
end
It seems to take issue with this line in particular:
#rental = #movie.rentals.build(params[:rental])
Here is the Rental model:
class Rental < ApplicationRecord
has_one :movie
end
Here is the controller for Movies:
class MoviesController < ApplicationController
def new
#movie = Movie.new
#movies = Movie.all
end
def create
#movie = Movie.new(movie_params)
if #movie.save
redirect_to new_movie_path
end
end
private
def movie_params
params.require(:movie).permit(:title, :year)
end
end
Here is the Movie model:
class Movie < ApplicationRecord
has_many :rentals
end
Here are the routes:
Rails.application.routes.draw do
resources :movies, :rentals
root 'movies#new'
end
Here is the form:
<h1><%= #movie.title %></h1>
<%= form_for #rental, :url => {:action => :create, :id => #movie.id } do |r| %>
Borrowed on: <%= r.text_field :borrowed_on %><br />
Returned on: <%= r.text_field :returned_on %><br />
<br />
<%= r.button :submit %>
<% end %>
<br />
<%= link_to "back", new_movie_path %>
I'm not sure what is going on. From what I can tell, I am copying the tutorial exactly. Any help would be much appreciated!

You aren't using strong params for rentals, hence the ActiveModel::ForbiddenAttributesError error.
This should fix the error:
class RentalsController < ApplicationController
def new
#movie = Movie.find(params[:id])
#rental = #movie.rentals.build
end
def create
#movie = Movie.find(params[:id])
#rental = #movie.rentals.build(rental_params)
if #rental.save
redirect_to new_rental_path(:id => #movie.id)
end
end
private
def rental_params
params.require(:rental).permit(:borrowed_on, :rented_on)
end
end

Related

How can I create a form without using resources (action :new, :create) in Rails?

This is my controller
class SchoolsController < ApplicationController
def teacher
#teacher = Teacher.new
end
def form_create
#teacher = Teacher.new(teacher_params)
if teacher.save
redirect_to schools_teacher_path
else
flash[:notice] = "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
This is my views/schools/teacher.html.erb
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
I am new to Ruby on Rails, and not sure how to proceed.
You should move this to a TeachersController let me show you how:
First you need to create the controller, you can get this done by typing this on the terminal at the project root directory:
$ rails g controller teachers new
Then into your route file (config/routes.rb):
resources :teachers, only: [:new, :create]
After that go to the teachers_controller.rb file and add the following:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def reate
#teacher = Teacher.new(teacher_params)
if #teacher.save
redirect_to schools_teacher_path
else
redirect_to schools_teacher_path, notice: "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
Then you can have the form at views/teachers/new.html.erb:
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Please let me know how it goes!

Ruby on Rails NoMethodError in Articles#show

I keep getting a no method error. Why? How can I fix this?
NoMethodError in Articles#show
undefined method `photo' for #
I am using ruby on rails and I'm trying to use paperclip so i can upload photos on my app
part of my show file
<%= render #article.photos %> #source of error
<h3>Add a photo:</h3>
<%= render 'photos/form' %>
my photos controller
class PhotosController < ApplicationController
#Index action, photos gets listed in the order at which they were created
def index
#photos = Photo.order('created_at')
end
#New action for creating a new photo
def new
#photo = Photo.new
end
#Create action ensures that submitted photo gets created if it meets the requirements
def create
#article = Article.find(params[:article_id])
#photo = #article.photos.create(photo_params)
redirect_to article_path(#article)
end
def destroy
#article = Article.find(params[:article_id])
#photo = #article.photos.find(params[:id])
#photo.destroy
redirect_to article_path(#article)
end
private
#Permitted parameters when creating a photo. This is used for security reasons.
def photo_params
params.require(:photo).permit(:title, :image)
end
end
========= UPDATE =======
This is my
articles controller
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
article model
class Article < ApplicationRecord
has_many :comments
end
I fixed it now, but now i have another no method error
undefined method `article_photos_path' for #<#:0x007f17f052d0a0>
Did you mean? article_path
<%= form_for([#article, #article.photos.build]) do |f| %> #source of error
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control'%>
</div>
<p>
<%= f.submit 'Upload Photo' %>
</p>
<% end %>
</p>
<% end %>
Being Photo another model so, you need to make the proper relationship:
class Article < ApplicationRecord
has_many :comments
has_many :photos
end
class Photo < ApplicationRecord
belongs_to :article
end
As I see in your photo_params, you don't have the article_id attribute then you must add it, running a migration:
$ rails g migration add_article_to_photos article:references
$ rails db:migrate
After that you should update them:
params.require(:photo).permit(:title, :image, :article_id)

Ruby rails. Undefined method error, creating nested resource object

I am trying to render a form to upload a song.
I have a playlist model and a song model, song being a nested resource of playlist.
With simple form, when I try and render the new song partial, I get undefined method songs_path for #<#<Class:0x007fdc51980870>
In routes, the new song path is new_playlist_song but it doesn't seem that simple form knows this.
Songs controller:
class SongsController < ApplicationController
def new
#song = Song.new
end
def create
#song = Song.new(song_params)
if #song.save
flash[:info] = "Song uploaded sensually"
redirect_to user_path(current_user)
else
render 'new'
end
end
def index
#song = Song.all
end
private
def song_params
params.require(:song).permit(:audio)
end
end
Playlists controller:
class PlaylistsController < ApplicationController
before_action :find_playlist, only: [:edit, :update, :destroy]
def index
#playlists = Playlist.all
end
def new
if user_signed_in?
#playlist = current_user.playlists.new
else
redirect_to(root_url)
flash[:danger] = "You have to register to purchase gigs"
end
end
def create
#playlist = current_user.playlists.new
#playlist.user_id = current_user.id
if #playlist.save
redirect_to new_playlist_path
else
render 'new'
end
end
def destroy
#playlist = Playlist.find(params[:id])
if #playlist.present?
#playlist.destroy
redirect_to playlists_path
end
end
private
def find_playlist
#playlist = Playlist.find(params[:id])
end
end
Song model:
class Song < ActiveRecord::Base
belongs_to :playlist
has_attached_file :audio
validates_attachment_presence :audio
validates_attachment_content_type :audio, :content_type => [ 'audio/mp3','audio/mpeg']
end
Playlist model :
class Playlist < ActiveRecord::Base
belongs_to :user
has_many :songs
end
Routes:
resources :playlists do
resources :songs
end
User profile link to create new song:
<p> <%= #user.playlist.user_id %> </p>
<p> <%= #user.playlist.created_at %> </p>
<% if #user == current_user %>
<p> <%= link_to "Uploaad track", new_playlist_song_path(#user) %>
<% end %>
I have tried a few variants for the simple_form form.
New song partial 1:
<%= simple_form_for ([#playlist, #song]) do |f| %>
<%= f.file_field :audio %>
<%= f.button :submit %>
<% end %>
another try :
<%= simple_form_for ([#playlist, current_user.playlist.songs.build]) do |f| %>
I just can't get the form to show and I can't figure out why not. Any ideas would be appreciated, thanks.
As pointed out in the comments songs_path is not referenced in your code, and shouldn't even exist as it's a sub-resource of playlist.
If you want to list all the available routes just run a rake routes and make sure the code references an existing path.
I didn't define the playlist that the song belongs to.
Adding to the controller
def create
#song = current_user.playlist.songs.new song_params
#song.playlist_id = #playlist.id
if #song.save
and
def find_playlist
#playlist = Playlist.find(params[:id])
end
then to simple form
<%= simple_form_for ([#playlist, #playlist.songs.build]) do |f| %>
It works.

Rails user rating, can only rate myself

I am trying to set up a 5 star rating system so users can rate other users. At the moment everything is working, (create, delete, update etc...) but only the logged in user can rate himself. I cannot rate other users. I get no errors, it just redirects to the user profile page as it should but without added a rating to that user.
user.rb
class User < ActiveRecord::Base
has_many :reviews
review.rb
class Review < ActiveRecord::Base
belongs_to :user
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :find_user
before_action :find_review, only: [:edit, :update, :destroy]
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
if #review.save
redirect_to user_path(#user)
else
render 'new'
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to user_path(#user)
else
render 'edit'
end
end
def destroy
#review.destroy
redirect_to user_path(#user)
end
private
def review_params
params.require(:review).permit(:rating, :comment)
end
def find_user
#user = User.find(params[:user_id])
end
def find_review
#review = Review.find(params[:id])
end
end
_form which then gets rendered on show page:
<%= simple_form_for([#user, #user.reviews.build]) do |f| %>
<div id="rating-form">
<label>Rating</label>
</div>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
<script>
$('#rating-form').raty({
path: '/assets/',
scoreName: 'review[rating]'
});
</script>
Any help getting this to work would be greatly appreciated!!
Do this:
#config/routes.rb
resources :users do
resources :reviews, only: [:new, :create]
end
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :reviewed, class_name: "User", foreign_key: :reviewed_id
end
#app/controllers/reviews_controller.rb
class ReviewsController < ApplicationController
def new
#review = current_user.reviews.new
end
def create
#review = current_user.reviews.new review_params
#review.save
end
private
def review_params
params.require(:review).permit(:rating, :comment).merge(reviewed_id: params[:user_id])
end
end
#app/views/reviews/new.html.erb
<%= form_for #review do |f| %>
<%= f.number_field :rating %>
<%= f.text_field :comment %>
<%= f.submit %>
<% end %>
This would mean you'll have to include a reviewed_id column in your reviews table.
You'll be able to access it using: url.com/users/:user_id/reviews/new
The application will automatically fill the user_id and reviewed_id fields, so the rest of your code should work with the upgrade.
The big problem you have is that you're basically recording the user_id (presumably of who created the review)... but have no way of stipulating who the review is about.
The above code fixes that for you.

No route matches while creating nested resource in Rails

I am trying to create a new teacher for a specific school in my project and I got this error:
No route matches [POST] "/schools/3/teachers/new"
Here is my teachers_controller.rb:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def create
#teacher = Teacher.new(teacher_params)
#teacher.save
redirect_to school_path(school)
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
end
schools_controller.rb:
class SchoolsController < ApplicationController
def show
#school = School.find(params[:id])
end
def new
#school = School.new
end
def edit
#school = School.find(params[:id])
end
def update
#school = School.find(params[:id])
if #school.update(school_params)
redirect_to #school
else
render 'edit'
end
end
def index
#schools = School.all
end
def create
#school = School.new(school_params)
if #school.save
redirect_to schools_path
else
render 'new'
end
end
def destroy
#school = School.find(params[:id])
#school.destroy
redirect_to schools_path
end
private
def school_params
params.require(:school).permit(:name)
end
end
routes.rb:
Rails.application.routes.draw do
resources :schools do
resources :teachers
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'welcome#index'
And teachers/new.html.erb:
<%= form_for :teacher, url: school_teachers_path(school) do |f| %>
<p>
<%= f.label :firstName %><br>
<%= f.text_field :firstName %>
</p>
<p>
<%= f.label :lastName %><br>
<%= f.text_field :lastName %>
</p>
<p>
<%= f.label :middleName %><br>
<%= f.text_field :middleName %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
As your teacher resource is nested under the school resource, so you need to pass the school when you try to create a teacher.
Try changing your new and create actions in teachers_controller.rb to something like this:
def new
#school = School.find(params[:school_id])
#teacher = #school.teachers.build
end
def create
#school = School.find(params[:school_id])
#teacher = #school.teachers.build(params[:teacher])
#teacher.save
redirect_to school_path(#school)
end
And, then change your form to this:
<%= form_for([#school, #teacher]) do %>
. . .
. . .
<% end %>
Try this in your form:
<%= form_for [school, Teacher.new] do |f| %>
The path you are posting to is for the index of teachers at a school:
school_teachers GET /schools/:school_id/teachers(.:format) teachers#index
I believe that it's a has_many belongs_to association. So you need to first change your teacher controller create action and new action.
class TeachersController < ApplicationController
def new
get_school
#teacher = #school.teachers.build
end
def create
get_school
#teacher = #school.teachers.build(teacher_params)
If #teacher.save
redirect_to school_path(school)
else
render 'new'
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
def get_school
#school = School.find (params [:school_id])
end
end
Then in your form you 'll do :
<%= form_for([#school,#teacher]) do |f| %>
Hope this will help

Resources