Destroy action on nested resource - ruby-on-rails

Im trying to add a destroy button on my nested resource and getting this error: No route matches [DELETE] "/users/1/2/4/5/holidays/7"
Heres the relevant parts of my view,routes, models, & controllers:
<% #user.holidays.each do |h| %>
<td><%= h.name %></td>
<td><%= h.date %></td>
<td>
<%= button_to('Destroy', user_holiday_path(#user.holidays), :method => 'delete', :class => 'btn btn-large btn-primary') %>
</td>
<% end %>
Routes
resources :users do
resources :interests
resources :holidays
end
Models
class User < ActiveRecord::Base
has_many :holidays, :through => :user_holidays
end
class UserHoliday < ActiveRecord::Base
attr_accessible :holiday_id, :user_id
belongs_to :user
belongs_to :holiday
end
class Holiday < ActiveRecord::Base
attr_accessible :name, :date
has_many :user_holidays
has_many :users, :through => :user_holidays
end
Controller
class HolidaysController < ApplicationController
def index
#user_holidays = Holiday.find(params[:user_id])
#holidays = #user_holidays.holidays
end
def new
end
def show
#holiday = Holiday.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #holiday }
end
end
def destroy
#holiday = Holiday.find(params[:id])
#holiday.destroy
end
end
Thanks!!!

Change this :
<%= button_to('Destroy', user_holiday_path(#user.holidays), :method => 'delete', :class => 'btn btn-large btn-primary') %>
to this:
<%= button_to('Destroy', user_holiday_path(h), :method => 'delete', :class => 'btn btn-large btn-primary') %>
Update
Change your destroy action from :
#holiday = Holiday.find(params[:id]) to
#user_holiday = UserHoliday.find(params[:id])
and in your view:
change
<% #user.holidays.each do |h| %>
to
<% #user.user_holidays.each do |h| %>
Your associations need some correction and should be as follows:
user has_many user_holidays
user_holiday has_one holiday
user_holidays belongs_to user
You can access name and holiday via your h object:
h.holiday.name
h.holiday.date

Related

Updating nested fields_for and collection_select in Rails

Really stumped here. I'm trying to get my form to update the categories on the edit form. Problem is, everything in my form updates when submitted except the categories. It ends up inserting the new category chosen like it's going through the create method instead of the update method, so when the edit form is shown again after submission, it keeps doubling the fields of categories. 1, then 2, then 4, then 8, etc. after each submission. Please please help anyone. Appreciate it.
views/blog_posts/edit.html.erb
<div class="col-md-6 col-md-offset-3 blog-submit">
<%= form_for #blog_post do |b| %>
<%= b.label :title %>
<%= b.text_field :title %><br>
<%= b.fields_for :categorizations do |cat| %>
<%= cat.label :category_name, "Category 1" %>
<%= cat.collection_select(:category_id, Category.all, :id, :category_name, {blank: "Select Category"}) %>
<%= link_to "Add Categories", new_category_path %>
<br>
<% end %>
<%= b.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
Blog_post controller:
class BlogPostsController < ApplicationController
protect_from_forgery
before_action :authenticate_admin!, only: [:new, :edit]
def index
#blog_posts = BlogPost.order(id: :desc)
end
def new
#blog_post = BlogPost.new
#blog_post.categorizations.build.build_category
#blog_post.categories.build
end
def edit
#blog_post = BlogPost.find(params[:id])
end
def create
#blog_post = BlogPost.new(blog_post_params)
respond_to do |format|
if #blog_post.save
format.html { redirect_to #blog_post, notice: 'Your blog was submitted successfully' }
format.json { render :show, status: :created, location: #blog_post }
else
format.html { render :new }
format.json { render json: #blog_post.errors, status: :unprocessable_entity }
end
end
puts #blog_post.errors.inspect
end
def update
#blog_post = BlogPost.find(params[:id])
if #blog_post.update_attributes(blog_post_params)
render 'show'
else
render 'edit'
end
end
def show
#blog_post = BlogPost.find(params[:id])
end
private
def blog_post_params
params.require(:blog_post).permit(:title, :content, :posted_by, :comments, :blog_pic, {categorizations_attributes: [:category_id, :category_name]})
end
end
models:
class BlogPost < ApplicationRecord
has_many :categorizations
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categorizations
has_many :comments
mount_uploader :blog_pic, BlogPicUploader
end
class Categorization < ApplicationRecord
belongs_to :blog_post
belongs_to :category
end
class Category < ApplicationRecord
has_many :categorizations
has_many :blog_posts, :through => :categorizations
end
Add id in blog_post_params as shown below. This will work for you.
def blog_post_params
params.require(:blog_post).permit(:title, :content, :posted_by, :comments, :blog_pic, {categorizations_attributes: [:id,:category_id, :category_name]})
end

Rails polymorphic posts associations and form_for in views

I've been having trouble setting up the form for a polymorphic "department" post in the department view. I followed the rails-cast tutorial for polymorphic associations here
Models:
class Course < ActiveRecord::Base
belongs_to :department, inverse_of: :courses
has_and_belongs_to_many :users, -> { uniq }
has_many :posts, as: :postable #allows polymorphic posts
end
class Department < ActiveRecord::Base
has_many :courses, inverse_of: :department
has_many :posts, as: :postable #allows polymorphic posts
has_and_belongs_to_many :users, -> {uniq}
end
class Post < ActiveRecord::Base
belongs_to :user, touch: true #updates the updated_at timestamp whenever post is saved
belongs_to :postable, polymorphic: true #http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
belongs_to :department, counter_cache: true #for counting number of posts in department
belongs_to :course, counter_cache: true
validates :department_id, :course_id, presence: true
end
config/routes
devise_for :users
devise_scope :users do
match '/users/:id', to: "users#show", via: 'get'
end
resources :departments do
resources :courses
resources :posts
end
resources :courses do
resources :posts
end
views/departments/show.html.erb
<div class="tab-pane" id="posts"><br>
<center><h3>Posts:</h3></center>
<%= render "posts/form", postable: #department %>
</div>
views/posts/_form.html.erb
<%= render "posts/wysihtml5" %>
<center><h3>Create New Post:</h3></center>
<%= form_for [#postable, Post.new] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
<%= f.label :description %>
<%= f.text_area :description, :rows => 3, class: "form-control" %>
<%= f.text_area :content, :rows => 5, placeholder: 'Enter Content Here', class: "wysihtml5" %>
<span class="pull-left"><%= f.submit "Create Post", class: "btn btn-medium btn-primary" %></span>
<% end %>
controllers/post_controller.rb
class PostsController < ApplicationController
before_filter :find_postable
load_and_authorize_resource
def new
#postable = find_postable
#post = #postable.posts.new
end
def create
#postable = find_postable
#post = #postable.posts.build(post_params)
if #post.save
flash[:success] = "#{#post.title} was sucessfully created!"
redirect_to department_post_path#id: nil #redirects back to the current index action
else
render action: 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#postable = find_postable
#posts = #postable.posts
end
...
private
def post_params
params.require(:post).permit(:title, :description, :content)
end
def find_postable #gets the type of post to create
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
controllers/departments_controller.rb
def show
id = params[:id]
#department = Department.find(id)
#course = Course.new
#course.department_id = #department
end
The error is "undefined method `posts_path' for #<#:0x0000010d1dab10>"
I think the error has something to do with the path in the form, but I don't know what. I've tried [#postable, #postable.posts.build] as well but that just gives me undefined method: PostsController.
Anybody know what's going on and how I can fix it?
#department is passed into the form partial as a local variable, but the form calls an instance variable:
# views/departments/show.html.erb
<%= render "posts/form", postable: #department %> # <------ postable
# views/posts/_form.html.erb
<%= form_for [#postable, Post.new] do |f| %> # <------ #postable
Thus, the namespaced route is not properly determined
[#postable, Post.new] # => departments_posts_path
[ nil , Post.new] # => posts_path
Checking your routes, posts are only accessible via nested routes. posts_path is not a valid route, it's method does not exist, and the error is correct: undefined method `posts_path'
Fix:
Set a #postable instance variable in the departments controller so that the form helper can use it:
def show
id = params[:id]
#postable, #department = Department.find(id) # <-- add #postable
#course = Course.new
#course.department_id = #department
end
Then you can simply call render in the view:
<%= render "posts/form" %>

Adding a upvote/score to an existing tasks controller in Ruby on Rails?

I'm very new to Rails and I'm attempting to build a Todo app with the ability to upvote Todos. Currently my Todo model is as follows;
class Todo < ActiveRecord::Base
belongs_to :user
belongs_to :house
default_scope { order("score, created_at DESC") }
end
My Todos controller is as follows;
class TodosController < ApplicationController
before_filter :authenticate_user!
before_filter :assign_house_from_invite!
before_filter :ensure_house!
def index
#todo = Todo.new user: current_user
#todos = current_user.house.todos
end
def create
#todo = Todo.new(todo_params.merge(user: current_user, house: current_user.house))
#todo.save
end
protected
def todo_params
params.require(:todo).permit(:task, :vote)
end
def assign_house_from_invite!
end
def ensure_house!
redirect_to new_house_path if current_user.house.nil?
end
end
and my Todos erb partial is;
<div class="row input-append">
<%= form_for(#todo, remote: true, id: "new_todo_form") do |t| %>
<%= t.text_field :task, :placeholder => "Add new task", :class => "span2", :id => "appendedInputButton", :type => "text" %>
<%= t.submit '+', :id =>'plus', :class => 'btn', :type => 'button' %>
<% end %>
</div>
<div id="todos" class="row">
<% #todos.each do |todo| %>
<%= render partial: 'todo', locals: {todo: todo} %>
<% end %>
</div>
I'm wondering what do I have to add to each of these to enable each task to have an initial score assigned of 0 and then for it to be able to be incremented when it is upvoted? Any help would be much appreciated.

Rails Link_to is linking to undesired view

My link_to in my view is going to a completely different "show.html.erb" than I'd like it to. I'm basically trying to understand why the "link_to #exhibit is linking to an "Investigation" profile. I think it may have to do with my routes file or the fact that its a "belong to" relationship...but can't seem to get it workin...what should that link_to be?
UPDATE: (AS PER BROIS QUESTION)
The missing misbehaving link_to is in the <%= link_to #exhibit do %> in show.html.erb
MY EXHIBIT.RB (MODEL)
class Exhibit < ActiveRecord::Base
attr_accessible :content, :investigation_id, :name, :user_id, :media, :media_html
belongs_to :investigation
has_many :categorizations
has_many :categories, :through => :categorizations
validates :name, presence: true, length: { maximum: 140 }
validates :content, presence: true
default_scope -> { order('created_at DESC') }
auto_html_for :media do
html_escape
image
youtube(:width => 400, :height => 250)
link :target => "_blank", :rel => "nofollow"
simple_format
end
MY EXHIBIT CONTROLLER:
class ExhibitsController < ApplicationController
include AutoHtml
def new
#exhibit = Exhibit.new
end
def show
#exhibit = Exhibit.find(params[:id])
end
def index
#exhibits = Exhibit.paginate(page: params[:page])
end
def create
#investigation = Investigation.find(params[:investigation_id])
#exhibit = #investigation.exhibits.create(params[:exhibit])
if #exhibit.save
flash[:success] = "You've successfully added etc etc..."
redirect_to investigation_path(#investigation)
else
render 'new'
end
end
end
MY ROUTES.RB
resources :sessions, only: [:new, :create, :destroy]
resources :investigations do
resources :players
end
resources :investigations do
resources :exhibits
end
LASTLY MY SHOW.HTML.ERB (INVESTIGATION PROFILE)
<% #investigation.exhibits.each do |exhibit| %>
<div class="row-fluid services_circles">
<%= link_to #exhibit do %>
<div class="media">
<div class="pull-left">
<%= exhibit.media_html %>
</div>
<div class="media-body">
<h4 class="media-heading"><%= exhibit.name %></h4>
<p><%= exhibit.content %></p>
</div>
</div>
<% end %>
<% end %>
ADDED THE INVESTIGATIONS CONTROLLER
class InvestigationsController < ApplicationController
def new
#investigation = Investigation.new
end
def show
#investigation = Investigation.find(params[:id])
end
def index
#investigations = Investigation.paginate(page: params[:page])
end
def create
#investigation = Investigation.new(params[:investigation])
if #investigation.save
flash[:success] = "You've successfully created..."
redirect_to #investigation
else
render 'new'
end
end
end
ADDED THE INVESTIGATION MODEL
class Investigation < ActiveRecord::Base
# belongs_to :user
has_many :players, dependent: :destroy
has_many :exhibits, dependent: :destroy
default_scope -> { order('created_at DESC') }
end
I appreciate the help...if i need to post any more info just let me know
IN YOUR : app/contorollers/exhibits_controller.rb
def show
#investigation = Investigation.find(params[:investigation_id])
#exhibit = Exhibit.find(params[:id])
end
IN YOUR : app/views/exhibits/show.html.erb
<%= link_to investigation_exhibit_path(#investigation, #exhibit) do %>
Maybe, I think.

How to add has_many :through details to a form RoR

I'm doing what appears to be a common learning app for Ruby on Rails, the recipe app. Specifically, working on recipes and ingredients as a has_many :through relationship. Through looking at a million examples and questions, I've got my many-to-many relationship setup and my multi-model form working, but I'd like to add an additional field and can't get it working. Feels like I'm close to understanding how this stuff works. Here are the quick details:
Models:
class Ingredient < ActiveRecord::Base
has_many :recipe_ingredients
has_many :recipes, :through => :recipe_ingredients
end
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
end
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
accepts_nested_attributes_for :ingredients, :recipe_ingredients
def new_recipe_ingredient_attributes=(recipe_ingredient_attributes)
recipe_ingredient_attributes.each do |attributes|
recipe_ingredients.build(attributes)
end
end
def existing_recipe_ingredient_attributes=(recipe_ingredient_attributes)
recipe_ingredients.reject(&:new_record?).each do |recipe_ingredient|
attributes = recipe_ingredient_attributes[recipe_ingredient.id.to_s]
if attributes
recipe_ingredient.attributes = attributes
else
recipe_ingredient.delete(recipe_ingredient)
end
end
end
def save_recipe_ingredients
recipe_ingredients.each do |recipe_ingredient|
recipe_ingredient.save(false)
end
end
end
Controller:
def create
#recipe = Recipe.new(params[:recipe])
if #recipe.save
redirect_to :action => 'show', :id => #recipe
flash[:notice] = "Your record has been saved."
else
render :action => 'new'
end
end
def update
params[:recipe][:existing_recipe_ingredient_attributes] ||= {}
#recipe = Recipe.find(params[:id])
if #recipe.update_attributes(params[:recipe])
redirect_to :action => 'show', :id => #recipe
flash[:notice] = "Your changes have been saved."
else
render :action => 'edit'
end
end
View:
<% form_for(#recipe) do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %>
etc.....
Ingredients:
<div id="recipe_ingredients">
<div class="recipe_ingredient">
<% new_or_existing = recipe_ingredient.new_record? ? 'new' : 'existing' %>
<% prefix = "recipe[#{new_or_existing}_recipe_ingredient_attributes][]" %>
<% fields_for prefix, recipe_ingredient do |ri_form| %>
<p>
<%= ri_form.collection_select(:id, Ingredient.find(:all), :id, :name, :include_blank => true) %>
<%= ri_form.text_field :amount %>
</p>
<% end %>
</div>
</div>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
Sorry for the wall of code, hopefully it makes sense. The thing I can't understand is why the "amount" text field doesn't work. I've tried a million different ways, but can't get it working. In this case, the error I get is "undefined method `amount' for #"
What key connection am I missing here? Thanks.
At first glance it appears you should simply replace:
<% fields_for prefix, recipe_ingredient do |ri_form| %>
with:
<%= fields_for prefix, recipe_ingredient do |ri_form| %>

Resources