I'm currently developing an app which allows users to post from their own account, but if they're an administrator of a group or venue, they can also post as that entity. I'm struggling converting the polymorphic association ideas from some of the other questions out there as generally they're all based around being able to comment on multiple things and not from multiple things.
I think my main issue is that I have my user's post form on the homepage, so it does not have an ID in the URL.
My post controller looks like this:
class PostsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
before_filter :load_postable
def index
end
def new
#post = Postabe.posts.new(post_params)
end
def create
#post = #postable.posts.build(post_params)
if #post.save
flash[:success] = "Post created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#post.destroy
redirect_to root_url
end
private
def post_params
params.require(:post).permit(:content)
end
def load_postable
resource, id = request.path.split('/')[1, 2]
resource_name = resource.singularize.classify
if resource_name == "User"
#postable = current_user
else
#postable = resource_name.constantize.find(id)
end
end
end
and my _post_form.html.erb partial:
<%= form_for ([#postable, #postable.post.new]), remote: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Create a Post..." %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
my related routes:
devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks", :registrations => "registrations" }
resources :users, :only => [:index] do
member do
get :favourite_users, :favourited_users
end
resources :posts
end
resources :venues do
resources :posts
end
resources :groups do
resources :posts
end
Models as follows:
class Post < ActiveRecord::Base
belongs_to :postable, polymorphic: true
end
class User < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
class Venue < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
class Group < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
It seems that I keep getting the error
Couldn't find Post without an ID
but I don't know why it's looking for a Post ID if it's not been created yet. Any help would be appreciated!
You have before_filter :load_postable in your controller. By default it will run for all the actions in your controller, even when the id is not specified. The error is thrown by #postable = resource_name.constantize.find(id), id is nil for index method.
Change this line to:
before_filter :load_postable, except: [:index]
Related
I am building a project management app.
My System is like- A project has many features, A feature has many tasks.
And the routes.rb is defined as
resources :projects do
resources :features do
resources :tasks
end
end
The first level , that is project to feature is working fine for new feature form , but when I try to implement new tasks form as ->
<%= form_for([#feature, #feature.tasks.build], class: "form-group row") do |form| %>
<%= form.label :name %>
<%= form.text_field :name, required:true, class: "form-control" %>
<%= form.submit class: "btn btn-primary m-2" %>
<% end %>
Now its showing error as
Here is my models->
class Task < ApplicationRecord
belongs_to :feature
end
class Feature < ApplicationRecord
belongs_to :project
has_many :tasks
end
And the controller for tasks looks like->
class TasksController < ApplicationController
before_action :set_feature
def new
#task = #feature.tasks.new
end
def create
#task = #feature.tasks.new(task_params)
if #task.save
redirect_to project_features_path
else
render :new
end
end
def edit
end
def update
if #task.update(task_params)
redirect_to project_feature_tasks_path
else
render :edit
end
end
def complete
#task.update(completed: true)
redirect_to project_feature_tasks_path
end
def destroy
#feature.task.destroy
redirect_to project_feature_tasks_path
end
private
def set_feature
#feature = Feature.find(params[:feature_id])
end
def task_params
params.require(:task).permit(:name,:completed, :project_id,:feature_id)
end
end
Any help is very much appreciated - I am stuck with this error for days now.
If you try running $ rails routes you can see why your current routes are failing you.
Prefix Verb URI Pattern Controller#Action
project_feature_tasks GET /projects/:project_id/features/:feature_id/tasks(.:format) tasks#index
POST /projects/:project_id/features/:feature_id/tasks(.:format) tasks#create
new_project_feature_task GET /projects/:project_id/features/:feature_id/tasks/new(.:format) tasks#new
edit_project_feature_task GET /projects/:project_id/features/:feature_id/tasks/:id/edit(.:format) tasks#edit
project_feature_task GET /projects/:project_id/features/:feature_id/tasks/:id(.:format) tasks#show
PATCH /projects/:project_id/features/:feature_id/tasks/:id(.:format) tasks#update
PUT /projects/:project_id/features/:feature_id/tasks/:id(.:format) tasks#update
DELETE /projects/:project_id/features/:feature_id/tasks/:id(.:format)
You would have to call:
form_for([#project, #feature, #feature.tasks.build], ...) do |form|
A better idea is to unnest the routes. You can do this by using the shallow option:
resources :projects do
resources :features, shallow: true do
resources :tasks
end
end
Or you can do it like so if you for some reason want to keep the member routes (show, edit, update, destroy) for features nested:
resources :projects do
resources :features
end
resources :features, only: [] do
resources :tasks
end
I am new to rails and building my first app. I can't figure how to assign a car_id to new instances of awards that get created with the views/awards/new.html.erb file. Can anyone take a look and see where I am going wrong?
awards controller:
class AwardsController < ApplicationController
before_action :set_award, only: [:show]
def new
#award = Award.new
end
def index
#awards = Award.all
end
def create
#car = Car.params
#award = Award.new(award_params)
#award.save
redirect_to user_path(current_user)
end
def show
end
def destroy
end
private
def set_award
#award = Award.find(params[:id])
end
def award_params
params.require(:award).permit(:title, :year, :description)
end
end
cars controller
class CarsController < ApplicationController
before_action :set_car, only: [:show, :edit, :update, :destroy]
def new
#car = Car.new
end
def index
#cars = Car.all
end
def create
#car = Car.new(car_params)
#car.save
current_user.cars << #car
redirect_to current_user, :flash => { :success => "car created!" }
end
def edit
end
def update
#car.update(car_params)
if #car.valid?
#car.save
redirect_to user_path(current_user)
else
render :edit
end
end
def show
#car = Car.find(params[:id])
end
def destroy
#car.destroy
redirect_to user_path(current_user)
end
private
def set_car
#car = Car.find(params[:id])
end
def car_params
params.require(:car).permit(:make,:model,:year,:color)
end
end
car.rb
class Car < ApplicationRecord
belongs_to :user
has_many :awards
end
award.rb
class Award < ApplicationRecord
belongs_to :car
has_one :user, through: :cars
end
routes
Rails.application.routes.draw do
resources :awards
resources :cars
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
resources :users
root 'welcome#home'
resources :users do
resources :cars
end
resources :cars do
resources :awards
end
end
#awards form
<%= form_for #award do |f| %>
<%= f.label :title %>
<%= f.text_field :title %><br>
<%= f.label :year %>
<%= f.text_field :year %><br>
<%= f.label :description %>
<%= f.text_area :description %><br>
<%= f.submit %>
<%end%>
I need to be able to assign awards to specific cars, does anyone know how I can go about doing this?
Since you are using nested routes:
resources :cars do
resources :awards
end
Then:
app/controllers/awards_controller.rb
class AwardsController < ApplicationController
# add more into the array as you need
before_action :set_car, only: [:new, :create]
def new
#award = #car.awards.new
end
def create
#award = #car.awards.new(award_params)
#award.save
redirect_to user_path(current_user)
end
private
def set_car
#car = Car.find(params[:car_id])
end
end
app/views/awards/new.html.erb
<%= form_for [#car, #award] do |f| %>
...
Trivia:
because you are using nested routes, then your links would be something like:
<%= link_to 'New Award', new_car_award_path(SOMECAR) %>
<%= link_to 'Awards', car_awards_path(SOMECAR) %>
<%= link_to 'Edit Award', edit_car_award_path(SOMECAR, SOMEAWARD) %>
<%= link_to 'Delete Award', car_award_path(SOMECAR, SOMEAWARD), method: :delete %>
...just replace SOMECAR and SOMEAWARD with a Car and Award instances respectively, that you want to be in that link.
Recommendations:
handle validations errors. See tutorial
If possible, use shallow nesting
I am new to Ruby on Rails.I am facing a problem using nested resources.
I am building a learning app where there are courses and lessons.
Every course will have many lessons and a lesson belongs to only one course.
I am unable to create a lesson for a course currently.
Example : http://localhost:3000/courses/19/lessons/new is a page where i want to create and display lessons for course 19.
Routes.rb
Rails.application.routes.draw do
devise_for :users
resources :courses
resources :courses do
resources :lessons
end
resources :lessons
root 'pages#landing'
get 'pages/home' => 'pages#home' ,as: :home
get '/user/:id' => 'pages#profile',as: :profile
get '/users' => 'courses#index',as: :user_root
end
Course.rb
class Course < ActiveRecord::Base
belongs_to :user
has_many :lesson
validates :user_id , presence: true
end
Lesson.rb
class Lesson < ActiveRecord::Base
belongs_to :course
validates :course_id , presence: true
end
CourseController.rb
class CoursesController < ApplicationController
def index
#courses = Course.all;
end
def new
#course = Course.new;
end
def create
#course = Course.new(course_params);
#course.user_id = current_user.id;
if #course.save
redirect_to course_path(#course)
else
flash[:notice]="Course could not be created ! "
redirect_to new_course_path
end
end
def edit
end
def update
end
def destroy
#course = Course.find(params[:id]);
#course.destroy;
end
def show
#course = Course.find(params[:id]);
end
private
def course_params
params.require(:course).permit(:title, :description, :user_id)
end
end
LessonController.rb
class LessonsController < ApplicationController
def index
#lessons = Lesson.all;
end
def new
#lesson = Lesson.new;
end
def create
#lesson = Lesson.new(lesson_params);
#course = Course.find_by(id: [params[:course_id]]);
if #lesson.save
redirect_to new_course_lesson_path , flash[:notice] = "Lesson successfully saved !"
else
redirect_to new_course_lesson_path , flash[:notice] = "Lesson cannot be created ! "
end
end
def show
#lesson = Lesson.find(params[:id])
end
private
def lesson_params
params.require(:lesson).permit(:title,:description,:video,:course_id)
end
end
Lessonform.html.erb
<%= form_for ([#course,#lesson]) do |f| %>
<%= f.label :lesson_Title %>
<%= f.text_field :title ,placeholder: "Enter the lesson Title" ,:class=>"form-control" %><br />
<%= f.label :Description %>
<%= f.text_area :description ,placeholder: "Enter the lesson Description",rows:"8",:class=>"form-control" %><br />
<center>
<%= f.submit "Create lesson",:class =>"btn btn-lg btn-primary" %>
</center>
<% end %>
One problem i see is that you have defined route resources :lessons twice. Once, inside courses scope and second time outside.
The error seems to occur because in your view #course is nil. So, please check you set #course in a before_action inside lessons_controller#new action.
EDIT
class LessonsController < ApplicationController
before_action :set_course, only: [:new, :create]
def new
#lesson = #course.lessons.build
end
private
def set_course
#course = Course.find_by(id: params[:course_id])
end
end
Also replace has_many :lesson with has_many :lessons inside Course model.
First change you need to make in your Course model as you have singular lesson when defining many association:
has_many :lessons
Also let me know if their are any chances of lessons page being called without courses? If no then please remove:
resources :lessons
I guess also the two defining of courses in routes in creating issue. Please try removing the:
resources :courses
Let me know if you still face any issue.
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 %>
I am dealing with a nested form on my current project and found a very simple blog post that has helped me alot http://iroller.ru/blog/2013/10/14/nested-model-form-in-rails-4/. The problem is that I cannot seem to update the event (which should in turn create the nested answers). I have spent most of the day today trying to work around this and I haven't been able to make any real progress.
Error
undefined local variable or method `event_params' for #<EventsController:0x007f9847af6d10>
Thanks guys and girls sorry for the dumb question. And please let me know if you would like any more information.
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
end
def event_params
params.require(:event).permit(:owner_id,
questions_attributes: [:poll, :event_id],
answers_attributes: [:response, :event_id, :question_id, :user_id])
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 %>
You have no method event_params, or probably it is not available for class. In your case it is in the another method:
def favorite
#arr = []
cookies.each do |cookie|
#arr.push(cookie)
endhtm
#info = []
for i in 0...#arr.length
if #arr[i][0].index('id')
#info.push(#arr[i][1])
end
#info
end
if #info == []
flash[:error] = "You don't have any events saved yet. Please select events of interest to you."
redirect_to events_path
else
#events = Event.all_events_by_asc_order.where(id: #info)
end
end
def event_params
params.require(:event).permit(
questions_attributes: [:poll, answers_attributes: [:response]])
end
end
Should be:
def favorite
#arr = []
cookies.each do |cookie|
#arr.push(cookie)
endhtm
#info = []
for i in 0...#arr.length
if #arr[i][0].index('id')
#info.push(#arr[i][1])
end
#info
end
if #info == []
flash[:error] = "You don't have any events saved yet. Please select events of interest to you."
redirect_to events_path
else
#events = Event.all_events_by_asc_order.where(id: #info)
end
end
end
def event_params
params.require(:event).permit(
questions_attributes: [:poll, answers_attributes: [:response]])
end
There is endhtm, seems like it was end + something.