Ruby rails. Undefined method error, creating nested resource object - ruby-on-rails

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.

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 form error

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

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.

Rails 3.2.13 undefined method `photos_path' with nested resources with CarrierWave

I was hoping someone can give me some insights on how nested resources and more specifically how to tie it with CarrierWave.
I'm getting an error undefined method 'photos_path' and am a bit stuck on how do go about getting this to work.
I want to be able to have the following urls
Create a new photo
site.com/animal/dog/photos/new
Show photo
site.com/animal/dog/photos/my-dog-in-the-park
Should I be using a nested form? any help is much appreciated.
My Routes
root to: "home#index"
resources :animal do
resources :photos
end
My home view
<%= link_to "Add Dog Photo", new_animal_photo_path(animal_permalink: "dog") %>
My _form partial
<%= form_for [#animal, #photo], :html => {:multipart => true} do |f| %>
<%= f.hidden_field :animal_permalink %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.file_field :image %>
</p>
<p>
</p>
<p><%= f.submit %></p>
<% end %>
My Photo model
class Photo < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
before_create :set_permalink
before_update :set_permalink
belongs_to :dog
mount_uploader :image, PhotoUploader
def set_permalink
self.permalink = title.parameterize
end
def to_param
permalink.parameterize
end
end
My Animal model
class Animal < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
has_many :photos
scope :dog, where(name: "Dog")
def to_param
permalink.parameterize
end
end
My PhotoController
class PhotosController < ApplicationController
def show
#photo = Photo.find(params[:id])
end
def new
#animal = Animal.find_by_permalink(params[:id])
#photo = Photo.new
end
def create
#photo = Photo.new(photo_params)
if #photo.save
flash[:notice] = "Successfully created photo."
redirect_to root_url
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(params[:id])
end
def update
#photo = Photo.find(params[:id])
if #photo.update_attributes(photo_params)
flash[:notice] = "Successfully updated photo."
redirect_to root_url
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully destroyed photo."
redirect_to root_url
end
private
def photo_params
params.require(:photo).permit(:title, :image, :animal_id)
end
end
Thanks for taking a look. Any help is much appreciated.
I've made a few adjustments to your code.
Notice I've added an "s" to animal
root to: "home#index"
resources :animals do
resources :photos
end
notice I've removed an "s" from animals. I've changed animal_permalink to id because that is the default that would be expected by a nested resource. Also, note that, in your photos controller new method you check for the "id" param, not the animal_permalink param.
new_animal_photo_path(id: "dog")
In your _form. set the value of the animal_permalink
<%= f.hidden_field :animal_permalink, value: #animal.permalink %>
This assumes that Photo will be able to recognize the animal_permalink attribute and that you've defined an animal.permalink method/attribute. I'm not familiar with the permalink approach, so you may have to fiddle around a bit, but this should steer you in the right direction (I would normally set the :dog_id/:animal_id attribute).
Let me know how that goes.

ActiveRecord::RecordNotFound - Couldn't find Keynote without an ID

I'm building an application that has a Keynote model and a Story model (as well as a User model that I implemented with Devise).
Keynotes have many Stories and a Story belongs to a Keynote.
I'm having problems creating new stories and I get the following error:
ActiveRecord::RecordNotFound in StoriesController#create
Couldn't find Keynote without an ID
The error happens on line 17 of stories_controller.rb which is
#keynote = Keynote.find(params[:keynote_id])
in the create method.
This is part of my stories_controller.rb
class StoriesController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#keynote = Keynote.find(params[:keynote_id])
#stories = #keynote.stories
end
def new
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.stories.build
end
def create
if user_signed_in?
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.current_user.stories.build(params[:story])
if #story.save
flash[:notice] = 'Question submission succeeded'
redirect_to keynote_stories_path
else
render :action => 'new'
end
end
end
This is my keynotes_controller.rb
class KeynotesController < ApplicationController
def index
#keynotes = Keynote.find :all, :order => 'id ASC'
end
def new
#keynote = Keynote.new
end
def show
#keynote = Keynote.find(params[:id])
end
def create
#keynote = Keynote.new(params[:keynote])
if #keynote.save
flash[:notice] = 'Keynote submission succeeded'
redirect_to keynotes_path
else
render :action => 'new'
end
end
end
Any help would be really appreciated.
Edit:
These are the Parameters when I try to create a new Story.
{"utf8"=>"✓",
"authenticity_token"=>"76odSpcfpTlnePxr+WBt36fVdiLD2z+Gnkxt/Eu1/TU=",
"story"=>{"name"=>"as"},
"commit"=>"Send"}
It looks like the ID for the Keynote is not being passed.
This is the view for StoriesController#new
<%= error_messages_for 'story' %>
<%= form_for #story do |f| %>
<p>
Question:<br />
<%= f.text_field :name %>
</p>
<p>
<%= submit_tag "Ask" %>
</p>
<% end %>
This is what I have in my routes.rb file:
get "keynotes/index"
get "users/show"
devise_for :users
get "votes/create"
get "stories/index"
resources :keynotes do
resources :stories
end
resources :stories do
get 'bin', :on => :collection
resources :votes
end
resources :users
root :to => 'keynotes#index'
I think this should do the trick:
<%= form_for #story do |f| %>
<%= hidden_field_tag 'keynote_id', #keynote.id %>
.
rest of the form stuff here
.
<% end %>
PS. Not sure if you will get the keynote_id in params[:keynote_id] or params[:story][:keynote_id] .. check out both.
NB: I think there would be a easier way to do it too, using fields_for or something similar, but I don't have access to a Rails setup at the moment to test that out.

Resources