View Doesn't Display After Method Is Called - ruby-on-rails

I have a projects.show.html page which shows a project and it's given tasks. The tasks are shown if their completed attribute is set to false (default). I have a method that converts the attribute to true, but when it loads the page, I get an error:
"ActiveRecord::RecordNotFound in ProjectsController#show
Couldn't find Project with 'id'=tasks
def show
#project = Project.find(params[:id])
#task = #project.tasks.build
end
"
Here's my code:
projects_controller
def show
#project = Project.find(params[:id])
#task = #project.tasks.build
end
Tasks_controller
def completed
#task = Task.find(params[:id])
#task.completed = true
#task.save
redirect_to project_path(#project)
end
Projects/show.html.erb
<% if #project.tasks.size > 0 %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td><%= task.notes %></td>
<td><% if !task.completed %><%= link_to "Mark Complete", 'tasks/#{:id}/completed' %></td>
<% end %>
<% end %>
<% end %>
</table>
Any help would be appreciated.

Here tasks/#{:id}/completed - you put id as a symbol while you need to pass real id. You should use Rails routes helper instead of tasks/#{:id}/completed and it will make your life easier.
In terminal: rails routes or rake routes.
Find the route you need
Replace your link with something like this link_to('My link', task_complete_path(task.id))
If this not helps you, please reply and provide also your route definition.

First of all, consider defining your routes like this:
resources :projects do
resources :tasks, shallow: true do
member do
patch :completed
end
end
end
(You can read more about nesting resources and adding more RESTful actions in the docs.)
Which will give you:
completed_task PATCH /tasks/:id/completed(.:format) tasks#completed
project_tasks GET /projects/:project_id/tasks(.:format) tasks#index
POST /projects/:project_id/tasks(.:format) tasks#create
new_project_task GET /projects/:project_id/tasks/new(.:format) tasks#new
edit_task GET /tasks/:id/edit(.:format) tasks#edit
task GET /tasks/:id(.:format) tasks#show
PATCH /tasks/:id(.:format) tasks#update
PUT /tasks/:id(.:format) tasks#update
DELETE /tasks/:id(.:format) tasks#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
Notice that you now have a named path for completed_task that responds to the PATCH HTTP verb.
Then, update app/views/projects/show.html.erb to include:
<% if #project.tasks.any? %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td>
<%= task.notes %>
</td>
<td>
<% unless task.completed %>
<%= link_to "Mark Complete", completed_task_path(task), method: :patch %>
<% end %>
</td>
</tr>
<% end %>
</table>
<% end %>
It looks to me like your table is malformed, so I tried to fix it. You may need to fiddle with that.
Your TasksController#completed action is also malformed. You try to redirect to project_path(#project), but you never define #project. It should look more like:
def completed
#task = Task.find(params[:id])
#task.update(completed: true)
redirect_to #task.project
end
This, naturally, assumes you've set up your Task and Project association correctly, something like:
class Task < ActiveRecord::Base
belongs_to :project
end
FYI, I just cloned your projects and added this to views/static/index.html.erb (naturally, '1' is just a dummy ID since I don't have any records in the DB):
<%= link_to "Test", completed_task_path(1), method: :patch %>
Which gave me:
<a rel="nofollow" data-method="patch" href="/tasks/1/completed">Test</a>
When I click on it, I get:
Started PATCH "/tasks/1/completed" for 127.0.0.1 at 2018-07-10 09:28:01 -0700
Processing by TasksController#completed as HTML
Parameters: {"authenticity_token"=>"euLDameHwkrCCMfTsPg5Znk2Mwuh7v6/O2wZFt6zGaRJzE9F1XMgGR1Uz2oYfpeQL//v/L1QtAEo7TDqsphIFw==", "id"=>"1"}

Figured it out, thanks #jvillian for your help.
Instead of using a method in my tasks controller to change the Task.completed attribute (originally a string), I created an enumerable (similar to a boolean in that it's binary) that can be switched from "incomplete" to "complete" whenever the method is called.
app/controllers/tasks_controller:
include ProjectsHelper
class TasksController < ApplicationController
def create
t = Task.new(task_params)
t.save
redirect_to project_path(t.project)
end
def update
t = Task.find(params[:id])
if t.user == current_user
t.update(completion_status: 'complete', completion_date: DateTime.now, completed: true)
t.project.update(last_completed: DateTime.now)
end
redirect_to :back
end
def toggle_status
#task = Task.find(params[:id])
if #task.incomplete?
#task.complete!
elsif #task.complete?
#task.incomplete!
end
redirect_to #task.project
end
private
def task_params
params.require(:task).permit(:user_id, :project_id, :notes)
end
Then for my model:
class Task < ApplicationRecord
enum status: [ :incomplete, :complete ]
belongs_to :user
belongs_to :project
validates :notes, presence: true
scope :completed, -> { where(completed: true) }
def self.completed
Task.completed
end
end
The enum status serves as a binary option, much like a boolean. Formerly a string, I was able to change method to simply 'flip' the value of the enumerable, and write the proper controller action in my project/show:
<% if #project.tasks.any? %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td>
<%= task.notes %>
<%= task.status %>
</td>
<td>
<% if !task.id.nil? %>
<%= link_to "Change Status", toggle_status_task_path(task) %>
<% end %>
</td>
</tr>
<% end %>
</table>
<% end %>

Related

ActiveRecord::RecordNotFound in EmployeesController#edit

I am getting an error when trying to edit an employee. The full error message is:
ActiveRecord::RecordNotFound in EmployeesController#edit
Couldn't find Company with 'id'=5 (*this varies depending on which company I click on)
Extracted source (around line #57):
def find_company
#company = Company.find(permitted_params[:company_id])
end
end
With this application I have companies and employees. I can add, show and delete employees within the companies but I am unable to edit them due to this error. I am new to Rails and am unsure where I have gone wrong.
routes.rb:
Rails.application.routes.draw do
get 'welcome/index'
resources :companies do
resources :employees
end
root 'welcome#index'
get 'companies/new'
end
Employees controller:
class EmployeesController < ApplicationController
before_action :find_company
before_action :set_employee, only: %i[show edit update destroy]
def index
#employees = #company.employees
end
def show
#employee = Employee.find(params[:id])
end
def new
#employee = #company.employees.build
end
def edit
#employee = Employee.find(params[:id])
end
def create
#employee = #company.employees.build(permitted_params[:employee])
if #employee.save
redirect_to company_employees_path(#company)
else
render 'new'
end
end
def update
if #employee.update(forename: permitted_params[:forename],
surname: permitted_params[:surname])
redirect_to company_employees_path(#company)
else
render 'edit'
end
end
def destroy
#employee.destroy
redirect_to company_employees_path(#company)
end
private
def set_employee
#employee = Employee.find(permitted_params[:id])
end
def permitted_params
params.permit!
end
def find_company
#company = Company.find(permitted_params[:company_id])
end
end
Companies controller:
class CompaniesController < ApplicationController
def index
#company = Company.all
end
def show
#company = Company.find(permitted_params[:id])
# #company = Company.first
end
def new
#company = Company.new
end
def create
#company = Company.new(permitted_params[:company])
if #company.save
redirect_to #company
else
render 'new'
end
end
def destroy
#company = Company.find(permitted_params[:id])
#company.destroy
redirect_to companies_path
end
private
def permitted_params
params.permit!
end
end
Rake routes output:
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
company_employees GET /companies/:company_id/employees(.:format) employees#index
POST /companies/:company_id/employees(.:format) employees#create
new_company_employee GET /companies/:company_id/employees/new(.:format) employees#new
edit_company_employee GET /companies/:company_id/employees/:id/edit(.:format) employees#edit
company_employee GET /companies/:company_id/employees/:id(.:format) employees#show
PATCH /companies/:company_id/employees/:id(.:format) employees#update
PUT /companies/:company_id/employees/:id(.:format) employees#update
DELETE /companies/:company_id/employees/:id(.:format) employees#destroy
companies GET /companies(.:format) companies#index
POST /companies(.:format) companies#create
new_company GET /companies/new(.:format) companies#new
edit_company GET /companies/:id/edit(.:format) companies#edit
company GET /companies/:id(.:format) companies#show
PATCH /companies/:id(.:format) companies#update
PUT /companies/:id(.:format) companies#update
DELETE /companies/:id(.:format) companies#destroy
root GET / welcome#index
companies_new GET /companies/new(.:format) companies#new
Company show.html.erb
<h3><%= #company.name %></h3>
<p><%= #company.details %></p>
<h3>Employees</h3>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Forename</th>
<th>Surname</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% for employee in #company.employees %>
<tr>
<td><%= employee.id %></td>
<td><%= employee.forename %></td>
<td><%= employee.surname %></td>
<td><%= link_to "Edit", edit_company_employee_path(employee), class: "btn btn-primary btn-sm" %></td>
</tr>
<% end %>
</tbody>
</table>
<%= link_to "Add Employee", new_company_employee_path(#company), class: "btn btn-primary" %>
<%= link_to "Back to companies List", companies_path, class: "btn btn-outline-primary" %>
Please can someone help?
Try to pass #company to edit_company_employee_path.
<%= link_to "Edit", edit_company_employee_path(#company, employee), class: "btn btn-primary btn-sm" %>

What's a proper way to implement delete all option on a basic index form

I have users that have posts.
<p id="notice"><%= notice %></p>
<h1>Listing Posts</h1>
<table>
<thead>
<tr>
<th>Comment</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.content %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_user_post_path %>
And in controller
def destroy
#user = #post.user
#post.destroy
respond_to do |format|
format.html { redirect_to user_posts_url(#user), notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
What's the proper way to implement a link and controller action to destroy all posts for a particular user?
Edit:
config/routes.rb
resources :users do
resources :posts, shallow: true
end
Edit 2:
resources :users do
#resources :posts, shallow: true
resources :posts, shallow: true do
delete :destroy_all, on: collection
end
end
gives no block given (yield) error
aww my bad.. Just found the error.. forgot to add : to collection
I would pass an array of post IDs only if selected posts need to be deleted. If you want to delete all posts for a particular user, then here's how I would approach it:
config/routes.rb
resources :users do
resources :posts do
delete :destroy_all, on: :collection
end
end
Here, on: :collection means that the route applies to the collection of posts; the route therefore looks like this:
/users/:user_id/posts/destroy_all
You can read more about adding member and collection routes in the Rails Guides:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
app/controllers/posts_controller.rb
def destroy_all
user = User.find(params[:user_id])
user.posts.destroy_all
# redirect somewhere
end
app/views/posts/index.html.erb
<%= link_to(
"Delete all posts!",
destroy_all_user_posts_path,
method: :delete
) %>
If you want to delete all posts for the current_user, modify like so:
config/routes.rb
resources :posts do
delete :destroy_all, on: :collection
end
app/controllers/posts_controller.rb
def destroy_all
current_user.posts.destroy_all
# redirect somewhere
end
app/views/posts/index.html.erb
<%= link_to(
"Delete all posts!",
destroy_all_posts_path,
method: :delete
) %>
Hope that helps.
I would create a separate controller method that accepts an array of post ids.
posts_controller.rb
def destroy_all
posts = Post.where(:id => params[:post_ids])
posts.delete_all
redirect_to :back
end
You will also need to supply the ids to the view method.
posts_controller.rb
def index
...
#posts_ids = Post.find(... how ever you need to select all posts...).pluck(:id)
...
end
views/posts/index.html.erb
...
<%= link_to destroy_all_posts_path(:post_ids => #posts_ids), :method => :destroy %>
...
You will also need to supply the route.
routes.rb
resources :users do
resources :posts
delete :destroy_all
end
end
And that should be it :)
You can use:
def destory_posts(user)
user.posts.destroy_all
render :nothing => true
end
add this method to your routes file.
Create a link like destory_posts_path(current_user) from where you want to delete the posts.

undefined method `jobs' for nil:NilClass

i'm a beginner in ruby on rails and getting an error i seem not to understand.
under the profile page for the Tradesman, i am trying to call all trades and all listed jobs under the trade. Trade has_many jobs & jobs has_many trades.
TrademanprofilesController:
class TrademanprofilesController < ApplicationController
def show
#user = current_user
end
def jobleads
end
def purchased
end
def memberBenifits
end
def account
end
def editjoblead
#trades = Trade.order(:name)
#jobs = Job.all
if params[:search].present?
#applications = Application.near(params[:search], 100, order: 'distance')
#hash = Gmaps4rails.build_markers(#applications) do |application, marker|
marker.lat application.latitude
marker.lng application.longitude
marker.infowindow application.location
marker.infowindow application.trade.name
end
else
#applications = Application.all
end
#applications_trades = #applications.group_by { |t| t.trade_id } end end
The views page which is a partial being called elsewhere. _trademanprofile_skills.html.erb:
<table>
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #trades.each do |trade| %>
<tr>
<td>
<%= trade.name %></br>
<ul><% #trade.jobs.each do |job| %></ul>
<li><%= job.name %></li>
<% end %>
</td>
<td><%= link_to 'Show', trade %></td>
</tr>
<% end %>
</tbody>
</table>
model: Trade.rb
class Trade < ActiveRecord::Base
attr_accessible :name, :job_ids
has_many :applications
has_many :jobs, through: :applications
end
model: Job.rb
class Job < ActiveRecord::Base
attr_accessible :name, :trade_ids
has_many :applications
has_many :trades, through: :applications
end
The error i get:
NoMethodError in Trademanprofiles#editjoblead
undefined method `jobs' for nil:NilClass
and highlights this line:
<ul><% #trade.jobs.each do |job| %></ul>
<li><%= job.name %></li>
<% end %>
i tried the below but did not work
<% #trades.each do |trade| %>
<%= trade.name %>
<%= trade.jobs %>
<% end %>
i got this displayed:
#<Job::ActiveRecord_Associations_CollectionProxy:0x00000106b0f1d8>
i also tried the below but did not work
<% #trades.each do |trade| %>
<%= trade.name %>
<%= trade.job_ids %>
<% end %>
but it only returned the id numbers of the jobs under the trade Aerial / Network
Aerial / Network Specialist
[978, 979, 980, 1039, 1040, 1041]
my routes file:
Rails.application.routes.draw do
resources :images
devise_for :users
resources :jobstartdates
resources :budgets
resources :applications do
collection do
get :search
get :search_result
get :business_details
end
end
get 'home/index'
resources :trades
resources :jobs
root to: 'home#index', as: 'home'
resource :trademanprofiles do
get :show
get :jobleads
get :purchased
get :memberBenifits
get :account
get :editjoblead
end
resources :employeenumbers
resources :businesstypes
resources :trademanroles
resources :titles
resources :adverts
resources :distances
i would like the Trade name & the Job names (not the ids) to be displayed. Many thanks an i truly apologise if this is a simple question.
If you look at your method
def editjoblead
#trades = Trade.order(:name) #this will return a collection of trades to you
#jobs = Job.all
#other logic
end
and in your view you have this
<ul>
<% #trade.jobs.each do |job| %></ul>
<li><%= job.name %></li>
<% end %>
First of all you need to correct your html you have closed ul and then using li and secondly you are trying to get a collection on a collection(#trade is a collection and jobs will give you a collection)
You need to do this:
<% #trades.each do |trade| %>
// this will give a single trade present in #trades
<tr>
<td>
<%= trade.name %></br>
<ul>
<% trade.jobs.each do |job| %>
// this will give a job associated with your trade, notice it's trade and not #trade
<li><%= job.name %></li>
<% end %>
</ul>
</td>
<td><%= link_to 'Show', trade %></td>
</tr>
<% end %>
what about your routes.rb file? I thing the error may be in there put like this in your route file
resources :trades do
resources :applications
resources :jobs
end

ActiveRecord::RecordNotFound Couldn't find Recipe with id=index

I am working on a Rails application, but came across the following error message.
ActiveRecord::RecordNotFound in RecipesController#show
Couldn't find recipe with id=index
Extracted source (around line #8)
def show
#recipe = Recipe.find(params[:id]) # This line is highlighted in pink
end
I believe this has to do with my routes. The url to my index page is localhost:3000/games/index (I'm calling the index action on my recipes controller. I created that action through resources :recipe creating seven restful routes including index.) However, when I access it, ROR thinks I'm accessing a game with id of index, through the show route. The truth is I would like to set my index page to localhost:3000/recipes. I don't want the index at the end.
Here is my RecipesController
class RecipesController < ApplicationController
def index
#recipe = Recipe.all
end
def show
#recipe = recipe.find(params[:id])
end
def new
#recipe = Recipe.new
end
def create
#recipe = Recipe.new(params[:id])
if #recipe.save
redirect_to #recipe
else
render 'new'
end
end
def edit
end
def update
end
def destroy
end
end
As you can see, I defined the 7 common RESTful routes and have finished 4 of them.
Here is my routes.rb file
Recipes::Application.routes.draw do
resources :recipes
end
By declaring resources :recipes, I created 7 routes without having to declare them on multiple lines.
Here is the result of rake routes
Prefix Verb URI Pattern Controller#Action
recipes GET /recipes(.:format) recipes#index
POST /recipes(.:format) recipes#create
new_recipe GET /recipes/new(.:format) recipes#new
edit_recipe GET /recipes/:id/edit(.:format) recipes#edit
recipe GET /recipes/:id(.:format) recipes#show
PATCH /recipes/:id(.:format) recipes#update
PUT /recipes/:id(.:format) recipes#update
DELETE /recipes/:id(.:format) recipes#destroy
Here is my index.html.erb file located in apps/views/recipes directory
<h1>Here is a list of recipes</h1>
<table>
<thead>
<tr>
<th>Recipe</th>
<th>Cook Time</th>
<th>Prep Time</th>
<th>Difficulty</th>
</tr>
</thead>
<tbody>
<% #recipes.each do |recipe| %>
<tr>
<td><%= recipe.recipe %></td>
<td><%= recipe.cooktime %></td>
<td><%= recipe.preptime %></td>
<td><%= recipe.difficulty %></td>
</tr>
<% end %>
</tbody>
</table>
Here is my migrations file
class CreateRecipes < ActiveRecord::Migration
def change
create_table :recipes do |t|
t.string :recipe
t.string :cooktime
t.string :preptime
t.integer :difficulty
t.timestamps
end
end
end
Here is my application.html.erb file used as a template for every webpage
<!DOCTYPE html>
<html>
<head>
<title>Recipes</title>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
<%= link_to "Home", recipes_path %>
<%= link_to "Edit", edit_recipe_path(:id) %>
<%= link_to "New", new_recupe_path %>
<%= link_to "Delete" %>
</body>
</html>
I tried creating ActiveRecord objects through rails console and had them saved. So ActiveRecord objects do exist with IDs. I don't know where I went wrong here.
If you need any more information, please let me know.
I appreciate any help. Thank you for your time.
what gives you this error? I could imagine calling /games/index would. Basically index is parsed as a parameter to the /games/:id route.
EDIT:
this is because of the <%= link_to "Edit", edit_game_path(:id) %> call in the layout template. Which is misplaced. You cannot edit if you are viewing /games because no :id is present.

Using thumbs_up gem while iterating

I'm using the thumbs_up gem in my application and I'm trying to figure out the best way to save votes in my controller while iterating.
Here is my model:
class Vendor < ActiveRecord::Base
has_many :inventory_items
has_many :items, through: :inventory_items
has_many :shopping_lists, through: :inventory_items
acts_as_voteable
end
my current controller:
def vote_for_vendor
# not sure what to put in here
end
def vote_against_vendor
# not sure what to put in here
end
my current view:
<% provide(:title, 'Stores') %>
<table class="table table-condensed table-hover">
<tr>
<th>Name</th>
<th>Address</th>
<th>Favorite?</th>
</tr>
<% #vendors.each do |v| %>
<tr>
<td><%= v.name %></td>
<td><%= v.address %></td>
<td>
<% if current_user.voted_for(v) %>
<%= link_to 'unlike', vote_against_vendor_vendors_path(vendor_id: v.id), :remote => true %>
<% else %>
<%= link_to 'like', vote_for_vendor_vendors_path(vendor_id: v.id), :remote => true %>
<% end %>
</td>
</tr>
</table>
Most of the examples I've seen have used params([]) to pass the relevant information to the controller. I don't really have params because this is just my index page that shows all vendors. How can I save votes using this gem while iterating? Thanks in advance!
Updated Controller w/ help from MrYoshi
class VendorsController < ApplicationController
def index
#vendors = Vendor.all
end
def vote_for_vendor
vendor = Vendor.find(params[:vendor_id])
current_user.vote_for(vendor)
respond_to do |format|
format.js
end
end
def vote_against_vendor
vendor = Vendor.find(params[:vendor_id])
current_user.vote_against(vendor)
respond_to do |format|
format.js
end
end
end
my routes:
resources :vendors do
collection { post :vote_for_vendor }
collection { post :vote_agaist_vendor }
end
Current Server Error
Started GET "/vendors/vote_for_vendor?vendor_id=4" for 127.0.0.1 at 2013-09-06 10:07:29 -0700
AbstractController::ActionNotFound (The action 'show' could not be found for VendorsController):
...........
Rendered /Users/#Myname/.rvm/gems/ruby-2.0.0-p195/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb within rescues/layout (0.5ms)
I give you the start of what you want, and you will be able to do the rest by yourself I think:
View:
<% if current_user.voted_for(v) %>
<%= link_to 'unlike', vote_against_vendor_vendors_path(vendor_id: v.id), :remote => true %>
<% else %>
<%= link_to 'like', vote_for_vendor_vendors_path(vendor_id: v.id), :remote => true %>
<% end %>
Controller:
def vote_for_vendor
vendor = Vendor.find(params[:vendor_id])
current_user.vote_for(vendor)
render :nothing => true
end
And the vote_against is pretty simple to guess now that you have this one above ;)
For your 'current server error' (AbstractController::ActionNotFound (The action 'show' could not be found for VendorsController):), you need to add a member route to your config/routes.rb file, like this:
resources :vendors do
member do
post 'vote_for_vendor'
post 'vote_against_vendor'
end
end
You are currently using collection routes which are for resources that don't need a particular ID to work. I highly recommend reading the Rails Guide on routes:
Rails Guide Documentation on Routes

Resources