I am getting following error :
undefined method `recommendations_path' for #<#<Class:0x0078>>
I have Recommendation model
class Recommendation < ActiveRecord::Base
belongs_to :user
belongs_to :recommended_user, class_name: "User", foreign_key: :recommended_user_id
end
I have user model
class User < ActiveRecord::Base
has_many :recommendations
................
end
In recommendation controller
def new
#recommendation = current_user.recommendations.new
end
In new.html.erb
<%= form_for #recommendation do |f| %>
<%= f.text_field :relationship %>
<%= f.text_field :comment %>
<%= f.submit %>
<% end %>
My routes, where I think problem is:
devise_for :users
resources :users, only: [:show] do
collection do
get :customer_signup
get :employee_signup
end
member do
get :choose_role
get :become_a_customer
get :become_a_employee
end
end
resources :users do
resources :recommendations
end
Thats actually when the form is trying to identify the path for your #recommendation.
According to your routes.rb your form must be:
<%= form_for [:user, #recommendation] do |f| %>
Related
So I am trying to implement a polymorphic association for the first time and I'm running into a little bit of trouble.
I am trying to allow users to leave a note on a contact or organization. But after I submit a note I run into a routing error.
Here is the error I'm receiving (image)
Here are my routes:
Here are my routes (screenshot)
Here is my routes.rb file:
Rails.application.routes.draw do
get 'welcome/index'
resources :organizations do
resources :contacts do
resources :notes, module: :contacts
end
resources :notes, module: :organizations
end
root 'welcome#index'
end
Here is my notes_controller.rb file:
class NotesController < ApplicationController
def create
#note = #noteable.notes.new note_params
redirect_to #noteable, notice: "Your note was successful!!!"
end
private
def note_params
params.require(:note).permit(:note_title, :note_body)
end
end
Here is my contacts/notes_controller.rb file:
class Contacts::NotesController < ApplicationController
private
def set_noteable
#noteable = Contact.find(params[:contact_id])
end
end
Here is my oranizations/notes_controller.rb file:
class Organizations::NotesController < ApplicationController
private
def set_noteable
#noteable = Organization.find(params[:organization_id])
end
end
Here is my view/notes/_form.html.rb file:
<h1>New Note</h1>
<%= form_for [noteable, Note.new] do |form| %>
<p>
<%= form.label :note_title %><br>
<%= form.text_field :note_title %>
</p>
<p>
<%= form.label :note_body %><br>
<%= form.text_area :note_body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
If you need anything else, I will provide it! Thank you ahead of time!
Try changing this:
resources :organizations do
resources :contacts do
resources :notes, module: :contacts
end
resources :notes, module: :organizations
end
to these lines:
resources :organizations do
resources :contacts do
resources :notes
end
resources :notes
end
You don't need the module there since they are already scoped by the parent resource.
Also move the contacts/notes_controller.rb to organizations/contacts/notes_controller.rb. Make sure you also move the view into the corresponding folder.
Hope it helps :)
I've been battling this for a while now and I can't figure it out. I have a user model using devise. Users can upload songs, and add youtube videos etc..
I'm trying to let users add/delete songs and videos from the devise edit registrations view.
Videos upload fine, but as songs are a nested resource of playlists, which belongs to user, I think I'm getting muddle up.
Music uploads with the same form on it's corresponding page, but not from the devise registration edit view.
routes:
devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }
resources :videos
resources :playlists do
resources :songs
end
Devise registrations controller:
def edit
#song = Song.new
#video = Video.new
end
Form in devise edit registrations:
<div id="user-music-box">
<p class="p-details-title"> Upload Music </p>
<%= simple_form_for [#user.playlist, #song] do |f| %>
<%= f.file_field :audio %>
<%= f.button :submit %>
<% end %>
</div>
<div id="user-video-box">
<p class="p-details-title"> Add videos </p>
<%= simple_form_for #video do |f| %>
<%= f.input :youtubeurl %>
<%= f.button :submit %>
<% end %>
</div>
As I said, videos (Which is a youtube url string) create and save no problem. The exact same form for songs, basically seems to just update the user registration. The song information is shown in the server logs, but no playlist_id is present and nothing gets saved.
Songs controller:
def new
if user_signed_in?
#song = Song.new
if current_user.playlist.songs.count >= 5
redirect_to user_path(current_user)
flash[:danger] = "You can only upload 5 songs."
end
else
redirect_to(root_url)
flash[:danger] = "You must sign in to upload songs"
end
end
def create
#song = current_user.playlist.songs.new song_params
#song.playlist_id = #playlist.id
if #song.save
respond_to do |format|
format.html {redirect_to user_path(current_user)}
format.js
end
else
render 'new'
end
end
Playlist.rb
class Playlist < ActiveRecord::Base
belongs_to :user
has_many :songs, :dependent => :destroy
accepts_nested_attributes_for :songs
end
song.rb
class Song < ActiveRecord::Base
belongs_to :user
belongs_to :playlist
has_attached_file :audio
validates_attachment_presence :audio
validates_attachment_content_type :audio, :content_type => ['audio/mp3','audio/mpeg']
end
Unless you're passing songs/playlists through accepts_nested_attributes_for you shouldn't be using registrations#edit. I'll detail both ways to achieve what you want below:
Nested Attributes
#app/models/user.rb
class User < ActiveRecord::Base
has_many :videos
has_many :playlists
has_many :songs, through: :playlists
accepts_nested_attributes_for :videos
end
#app/models/playlist.rb
class PlayList < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :songs
end
#app/models/song.rb
class Song < ActiveRecord::Base
has_and_belongs_to_many :playlists
end
The importance of this is that to use it properly, you're able to edit the #user object directly, passing the nested attributes through the fields_for helper:
#config/routes.rb
devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }
#app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update]
def edit
#user = current_user
#user.playlists.build.build_song
#user.videos.build
end
def update
#user = current_user.update user_params
end
private
def user_params
params.require(:user).permit(:user, :attributes, videos_attributes: [:youtubeurl], playlists_attributes: [song_ids: [], song_attributes: [:title, :artist, :etc]])
end
end
This will allow you to use:
#app/views/users/registrations/edit.html.erb
<%= form_for #user do |f| %>
<%= f.fields_for :videos do |v| %>
<%= v.text_field :youtubeurl %>
<% end %>
<%= f.fields_for :playlists do |p| %>
<%= p.collection_select :song_ids, Song.all, :id, :name %>
<%= p.fields_for :song do |s| %>
<%= f.text_field :title %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
This will give you a single form, from which you'll be able to create videos, playlists and songs for the #user.
Separate
The other option is to create the object separately.
There is no technical reason for preferring this way over nested attributes; you'd do it to make sure you have the routes in the correct order etc.
As a note, you need to remember that routes != model structure. You can have any routes you want, so long as they define a good pattern for your models:
# config/routes.rb
authenticated :user do #-> user has to be logged in
resources :videos, :playlists, :songs #-> url.com/videos/new
end
# app/controllers/videos_controller.rb
class VideosController < ApplicationController
def new
#video = current_user.videos.new
end
def create
#video = current_user.videos.new video_params
#video.save
end
private
def video_params
params.require(:video).permit(:youtubeurl)
end
end
# app/views/videos/new.html.erb
<%= form_for #video do |f| %>
<%= f.text_field :youtubeurl %>
<%= f.submit %>
<% end %>
The above will require the duplication of the VideosController for Playlists and Songs
I hope I am not asking an obvious question/ wont get down voted to hell for this.I am working on rails app and I am getting a "param is missing or the value is empty" error.
I have an event and questions that have already been created and I am using a nested form to allow the user to answer all the questions at once.
I am using rails 4
Models
class Event < ActiveRecord::Base
belongs_to :user
has_many :questions
accepts_nested_attributes_for :questions, allow_destroy: true
end
class Question < ActiveRecord::Base
belongs_to :user
belongs_to :event
has_many :answers
accepts_nested_attributes_for :answers, allow_destroy: true
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
Routes.rb
Rails.application.routes.draw do
root 'home#index'
devise_for :users, path_names: {sign_in: "login", sign_out: "logout"}, controllers: {omniauth_callbacks: "omniauth_callbacks"}
resources :answers
resources :users, only: [:new, :create]
resources :questions do
resources :answers #-> domain.com/questions/1/answers/new
end
resources :events, only: [:index, :new, :show, :update] do
patch ":id", action: :index
collection do
get :favorite
get "question/:id", action: :question
end
end
get 'users/new', to: 'users#new'
post 'users/new', to: 'users#create'
get 'events/favorite', to: 'events#favorite', via:[:get], as: 'favorite'
post 'events/:id' => 'events#update'
get 'answers/new' => 'answers#new'
get 'events/question' => 'events#question'
end
answers controller
class AnswersController < ApplicationController
def new
#event = Event.find(params[:id])
#answer = Answer.new
end
def show
end
def create
#answer = Answer.new(answer_params)
#answer.save
redirect_to events_path, notice: "Answered Questions"
end
private
def answer_params
params.require(:answer).permit(:response, :question, :event, :user, :event_id, :question_id, :user_id)
end
end
This is where my issue lies. Originally I had a very generic nested from a la http://railscasts.com/episodes/196-nested-model-form-revised but I switched the form_for down to the #answer because that is whats being created and switched to a button_to because the submit button was not writing the answer to the DB.(I believe it was trying to trigger something with #event )
<h1>New answers</h1>
<%= fields_for #event do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :questions do |b| %>
<p>
<%= b.text_field :poll%><br />
<%= form_for #answer do |x| %>
<%= x.text_field :response %>
<% end %>
</p>
<% end %>
<%= button_to "New", action: "create"%>
<% end %>
<%= link_to 'Back', answers_path %>
Please let me know if you need anymore code or have any questions
Thanks!
UPDATE
I have reworked my code based off this blog post http://iroller.ru/blog/2013/10/14/nested-model-form-in-rails-4/
now I am running the update through the events controller or at least I'm trying to.
The code is as follows, the error im getting now is
undefined local variable or method `event_params' for #
Thanks guys and girls sorry for the dumb questions
Models
class Event < ActiveRecord::Base
belongs_to :user
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ActiveRecord::Base
belongs_to :user
belongs_to :event
has_many :answers
accepts_nested_attributes_for :answers
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
Routes.rb
Rails.application.routes.draw do
root 'home#index'
devise_for :users, path_names: {sign_in: "login", sign_out: "logout"}, controllers: {omniauth_callbacks: "omniauth_callbacks"}
resources :answers
resources :users, only: [:new, :create]
resources :questions do
resources :answers #-> domain.com/questions/1/answers/new
end
resources :events, only: [:index, :new, :show, :update] do
patch ":id", action: :index
collection do
get :favorite
get "question/:id", action: :question
end
end
get 'users/new', to: 'users#new'
post 'users/new', to: 'users#create'
get 'events/favorite', to: 'events#favorite', via:[:get], as: 'favorite'
post 'events/:id' => 'events#update'
get 'answers/new' => 'answers#new'
get 'events/question' => 'events#question'
end
methods from events_controller
def question
#event = Event.find(params[:id])
end
def update
#event = Event.find(params[:id])
if #event.update(event_params)
redirect_to events_path, notice: "Answers saved"
else
redirect_to events_question_path, notice: "Answers not saved"
end
questions.erb
<%= simple_form_for(#event) do |f| %>
<%= f.error_notification %>
<%= f.object.name %>
<%= f.simple_fields_for :questions, f.object.questions do |q| %>
<%= q.object.poll%>
<%= q.simple_fields_for :answers, q.object.answers.build do |a|%>
<%= a.text_field :response %>
<% end %>
<%end %>
<%= f.button :submit%>
<% end %>
When i try to submit the form below i get this error WARNING: Can't mass-assign protected attributes: sub_category.I have tried to go over previous asked related questions here on stackoverflow and seems like i am in the right track ,but for some reason i am still getting the same error,what am i doing wrong?.I have included all the info below, thank you in advance.
View/form
<%= form_for #ip ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :email %>
<% f.text_field :ip_address %>
<%= f.fields_for :sub_category do |s| %>
<%=s.text_field :name%>
<%end%>
<%=f.submit "submit" %>
<%end%>
Controller
def create
#ips=Ip.new(params[:ip])
#ip=#ips.sub_categories.build
if #ip.save
redirect_to :controller=>"home" ,:action=>"index"
else
render 'index'
end
Models
class Ip < ActiveRecord::Base
has_many :sub_categories ,:through=>:ip_subs
has_many :ip_subs
accepts_nested_attributes_for :sub_categories
attr_accessible :sub_categories_attributes,:ip_address,:email,:ip_count
end
class SubCategory < ActiveRecord::Base
has_many :ip ,:through=>:ip_subs
has_many :ip_subs
end
class IpSub < ActiveRecord::Base
belongs_to :ip
belongs_to :sub_category
end
You should use f.fields_for :sub_categories (association name).
And don't forget to build association before render the form:
# in controller
def new
#ip = Ip.new
#ip.sub_categories.build
end
rubyonrails api :: fields_for
I am trying to follow Ryan Bates screencast but have an error message. I did the following:
1) Create table
class CreateComments < ActiveRecord::Migration
def self.up
create_table :comments do |t|
t.references :commentable, :polymorphic => true
2) Setup models
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
has_many :comments, :as => :commentable
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
has_many :comments, :as => :commentable
3) Change controller show action
class CategoriesController < ApplicationController
def show
#category = Category.find_by_permalink(params[:id])
#commentable = #category
#comment = Comment.new(:commentable => #category)
end
4) Add a form to template views/categories/show.html.erb
<% form_for [#commentable, Comment.new] do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :content %><br />
<%= f.text_area :content %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
5) After that I get error message by accessing /categories/my-category-permalink
NoMethodError in Categories#show
undefined method `category_comments_path' for #<ActionView::Base:0x69a9254>
Could you help me to understand what I did wrong?
In the original screencast Ryan accesses comments by /categories/permalink/comments using nested associations, but I don't need that. I want to write comments directly from my polymorphic objects.
Thanks
The problem was in routes settings. I thought that since I don't use nested resources, I can keep routes unchanged. Well, now I know that I was wrong... :) Add this to fix the problem:
map.resources :categories :has_many => :comments
map.resources :products, :has_many => :comments