How to link_to correct show page from feed? - ruby-on-rails

If a user clicks on:
activities/valuations/_create.html.erb
<%= link_to valuation_path(activity) do %>
<%= activity.trackable.name %>
<% end %>
he is directed to, for example, the error:
Couldn't find Valuation with 'id'=24
because the valuation is actually 7. This is because this line of code is trying to find the valuation show page by looking at the id number as an activity instead of the id number as a valuation.
To fix it I tried:
<%= link_to valuation_path(#valuation) do %>
<%= activity.trackable.name %>
<% end %>
but that gives the error:
ActionController::UrlGenerationError in Activities#index
No route matches {:action=>"show", :controller=>"valuations",
:id=>nil} missing required keys: [:id]
How do we rewrite the code to take the user to the correct valuations show page?
activities_controller
class ActivitiesController < ApplicationController
def index
#activities = Activity.order("created_at desc").paginate(:page => params[:page])
end
def show
redirect_to(:back)
end
def like
#activity = Activity.find(params[:id])
#activity_like = current_user.activity_likes.build(activity: #activity)
if #activity_like.save
#activity.increment!(:likes)
flash[:success] = 'Thanks for liking!'
else
flash[:error] = 'Two many likes'
end
redirect_to(:back)
end
end
activity.rb
class Activity < ActiveRecord::Base
self.per_page = 20
has_many :notifications
belongs_to :user
belongs_to :trackable, polymorphic: true
def conceal
trackable.conceal
end
def page_number
(index / per_page.to_f).ceil
end
private
def index
Activity.order(created_at: :desc).index self
end
end
activities/index
<% #activities.each do |activity| %>
<%= link_to activity.user.name, activity.user %></b>
<%= render "activities/#{activity.trackable_type.underscore}/#{activity.action}", activity: activity %>
<% end %>

it seems like you want to do a nested resource,
when you have activities/valuations/_create.html.erb , that means you should have a nested route
#routes.rb
resources :activities do
resources :valuations
end
So your link should be something like
<%= link_to 'link', activities_valuataions_path(activity, #validation) %>
if you could post your routes
rake routes
it should be easy to track down the problem

Related

How to get all jobs for current user and view every job

Missing keys required [:id] for child association show path
I have a job model that belongs to a user. In the user show page, I call all child jobs that belong to the user. Here is my code:
<% current_user.jobs.each do |j| %>
<%= j.id %>
<%= j.job_category %>
<%= link_to 'show', job_path(j.id) %> <br> <br>
<% end %>
But it raises an error anytime I click on show jobs page:
No route matches {:action=>"show", :controller=>"jobs", :id=>nil, :user_id=>"1"} missing required keys: [:id]
Please, how do I rectify this error? the routes show jobs resources stands on its own with path: job_path. it works when I manually plug in the URL.
Here are my routes.rb:
resources :users do
resources :jobs
resources :applications
end
resources :jobs do
collection do
match 'search' => 'jobs#search', via: [:get, :post], as: :search
end
end
and my controller code is:
class JobsController < ApplicationController
def index
#q = Job.ransack(params[:q])
#jobs = #q.result(distinct: true)
end
def frontpage
#q = Job.ransack(params[:q])
if params[:q].present?
redirect_to jobs_path(#q)
end
#jobs = Job.all
end
def search
index
render :index
end
def show
#job = Job.find(params[:id])
end
def edit
end
def update
#joblists.update(joblists_params)
redirect_to joblists_path
end
def create
#user = User.find(params[:user_id])
#user_job = #user.jobs.create(joblists_params)
flash[:notice] = "Job has been successfully Created"
redirect_to user_path(#user)
end
def joblists_params
params.require(:job).permit(:job_category, :job_title, :company_name, :location, :job_description,
:monthly_salary, :deadline, :contact, :longitude, :lattitude, :full_time )
end
end
Look after running rails routes it showing like this
user_job GET /users/:user_id/jobs/:id(.:format) jobs#show
so the link path is
user_job_path
on this link, you need to pass the user_id and job id then it will like this
<%= link_to 'show', user_job_path(#user, j.id) %> # or #user.id
Solved after chat
<% current_user.jobs.each do |j| %>
<%= j.id %>
<%= j.job_category %>
<%= link_to 'show', user_job_path(current_user.id, j.id) %> <br><br>
<% end %>
Add user id
user_job_path(current_user.id, j.id)
Thanks for comment

How to load all associations across all models

I'm making a simple website to learn RoR. It allows users to post reviews for movies, but I want to implement a link in my root view that shows ALL of the reviews in the database. How do I do that?
I want to be able to <%= link_to 'Reviews', reviews_path %> but my reviews#index URI pattern is /movies/:movie_id/reviews
What do I put in my reviews model in order to extract all the reviews in the database?
My reviews controller:
class ReviewsController < ApplicationController
def create
#movie = Movie.find(params[:movie_id])
#review = #movie.reviews.create(review_params)
redirect_to movies_path(#movie)
end
private
def review_params
params.require(:review).permit(:email, :comment)
end
end
Review model:
class Review < ApplicationRecord
belongs_to :movie
end
And my root view:
<h3>All Reviews:</h3>
<!-- put link here -->
<h3>Sort By:</h3>
<p>
<%= link_to 'Release', movies_path(:sort_param => "release") %>
<%= link_to 'Title', movies_path(:sort_param => "title") %>
</p>
<h1>Popular Movies</h1>
<% #movies.each do |m| %>
<h2>Title</h2>
<%= m.title %>
<%= m.release %>
<%= link_to 'Show', movie_path(m) %>
<% end %>
Edit: I looked at this solution but I'm not sure where to put that code. I tried to put it in the Review's index method but I got an error:
Couldn't find all Reviews with 'id': (all, {:order=>"created_at DESC", :limit=>10})
In your routes.rb
resources :reviews, only: [:index]
reviews_controller.rb
If you want to display all the reviews from any movie, in most recent order, you could do:
class ReviewsController < ApplicationController
def index
#reviews = Review.order('created_at DESC').limit(10)
end
def create
...
end
end
You can add a route to reviews only in your routes.rb file.
resources :reviews, only: [:index]

Adding comments to article in Rails 5 (deeply nested resources)

I have a Rails app that has three main models: Qn, Ans, and Comments. I've been doing okay with 1-level-deep nested resources, but these three resources are nested deeply (Comments is shallowly nested) and they are all displayed in one single view, which makes it very confusing.
In a url like: http://localhost:3000/questions/2, the user can see all #question.answers displayed using a loop. In each of those answers, the user can see the answer.comments displayed using a loop. Below each answer, the user can also submit a new comment.
But after attempting several times to implement a 1) loop displaying all comments and 2) form for new comment, I always get some error along the lines of:
undefined method `model_name' for {:url=>"/questions/4/answers/2/comments/new"}:Hash
So I tried to pass in params #commentable instead of the answer, or point to the specific controller and action and so on, but none of these methods worked. I am guessing that I have an issue with my controllers to begin with, but I cannot seem to figure out what.
routes.rb (top ommited)
# Resources
resources :sessions
resources :users
resources :bookmarks # to be implemented later
resources :questions do
resources :answers do
resources :comments, shallow: true
end
end
Question model
class Question < ApplicationRecord
has_many :answers
has_many :bookmarks #later
end
Answer model:
class Answer < ApplicationRecord
belongs_to :question
has_many :comments, as: :commentable
has_many :likes, as: :likeable
validates :answercontent, length: {minimum: 50}
end
Comment model:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
The show.html.erb (of QuestionsController)
<% #question.answers.each do |answer| %>
// ommited
<!-- Comments -->
<% answer.comments.each do |comment| %>
<%= comment.content %>
<br>
<% end %>
<!-- Submit new comment -->
<%= form_for(url: new_question_answer_comment_path, comment: {answer_id: answer.id, question_id: #question.id}) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Submit" %>
<% end %>
<% end %>
QuestionsController (new, create, destroy ommited for brevity)
class QuestionsController < ApplicationController
def index
#questions = Question.all
end
def show
#question = Question.find(params[:id])
#answers = Answer.all
# Delete only appears when num_ans is 0
#deletable = (current_user== User.find(#question.user_id)) && (#question.answers.all.size==0)
end
private
def question_params
params.require(:question).permit(:picture_url, :country, :educational_level, :topic)
end
end
AnswersController (edit, update, destroy ommited for brevity)
class AnswersController < ApplicationController
def create
#question = Question.find(params[:question_id])
#answer = #question.answers.create(answer_params)
#answer.question_id = #question.id
#answer.user_id = current_user.id
if #answer.save
redirect_to #question
else
render :new
end
end
private
def answer_params
params.require(:answer).permit(:user_id, :question_id, :answercontent)
end
end
CommentsController
class CommentsController < ApplicationController
before_filter: load_commentable
def index
#commentable = Answer.find(params[:answer_id])
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
if #comment.save
redirect_to #commentable
else
render :new
end
end
# From RailsCast ep.154
private
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
end
The routes
are quite messy right now so I will just post where the comments are:
question_answer_comments GET /questions/:question_id/answers/:answer_id/comments(.:format) comments#index
POST /questions/:question_id/answers/:answer_id/comments(.:format) comments#create
new_question_answer_comment GET /questions/:question_id/answers/:answer_id/comments/new(.:format) comments#new
edit_comment GET /comments/:id/edit(.:format) comments#edit
comment GET /comments/:id(.:format) comments#show
PATCH /comments/:id(.:format) comments#update
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy
Thanks in advance for the help.
Update:
To give you more info on what solutions I attempted:
1. Passing in two params like:
<%= form_for([answer, #comment], url: new_question_answer_comment_path(answer.id, #question.id)) do |f| %>
Gave me:
First argument in form cannot contain nil or be empty
Using #commentable (which is basically the answer) gives me an error saying that 'the id in #commentable.id doesn't exist as #commentable is nil'.
So I think the problem is that answer or #commentable is nil. But I specified it in the loop and in the controller too. So what else may I try?
form_for expects record as first argument, in your case it should be a comment instance. Also new_question_answer_comment_path expects values for question_id and answer_id keys, as you are creating a new comment, the route should be question_answer_comments not new_question_answer_comment so your form_for should be
<%= form_for Comment.new,url: question_answer_comments_path(#question,answer) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Submit" %>
<% end %>
or just
<%= form_for [Comment.new,#question,answer] do |f| %>
<%= f.text_area :content %>
<%= f.submit "Submit" %>
<% end %>

How do I place instances on a page without access to params in my create method?

I have three models, Subscription, Show, and Episode. Subscription's role is to parse the feed in its :url column and instantiate Show and Episode, filling their columns with Feedjira properties.
I'm only able to access the episodes when I go to shows/1/episodes/1, using <%= render #show.episodes %> in the Shows show view doesn't work and doesn't give any errors.
In the Rails getting started guide, they used this as their Comment create method, which allowed for that.
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
Is it the lack of params that's causing this? If so, how would I use params in this method?
def create
#subscription = Subscription.new(subscription_params)
if #subscription.save
#show = Show.new
#episodes = []
# Feed
#feed = Feedjira::Feed.fetch_and_parse #subscription.url
# Show
#show.title = #feed.title
#show.description = #feed.description
#show.genre = #feed.itunes_categories
#show.url = #feed.url
#show.logo = #feed.itunes_image
#show.save
# Episode
#feed.entries.each do |item|
#episodes.push(item)
end
#episodes.each do |item|
#episode = #show.episodes.create
#episode.title = item.title
#episode.description = item.summary
#episode.release_date = item.published
#episode.show_id = #show
#episode.save
end
redirect_to #subscription
end
end
episodes/_episode.hmtl.erb
<ul>
<li>
<%= episode.title %>
</li>
<li>
<%= episode.description %>
</li>
<li>
<%= episode.url %>
</li>
<li>
<%= episode.release_date %>
</li>
<li>
<%= episode.show_id %>
</li>
</ul>
shows/show.html.erb
<h1>Showing Show</h1>
<h2><%= #show.title %></h2>
<%= render #show.episodes %>
Adding my routes and models in case that's the issue:
routes.rb
Rails.application.routes.draw do
resources :shows do
resources :episodes
end
resources :subscriptions
root 'subscriptions#index'
end
show.rb
class Show < ActiveRecord::Base
has_many :episodes, dependent: :destroy
end
episode.rb
class Episode < ActiveRecord::Base
belongs_to :show
end
subscription.rb
class Subscription < ActiveRecord::Base
validates :url, uniqueness: true
end
Seems you need to just change
<%= render #show.episodes %>
to
<%= render partial: "episodes/episode", collection: #show.episodes %>
http://guides.rubyonrails.org/action_view_overview.html#partials
And small advice: don't place your logic in controller.

Voting for nested objects using the Acts As Votable gem

I have a Restaurant model that has_many :dishes, through: dish_categories. I found a post that shows how to write the view code necessary to get things going for the Acts As Votable gem. My situation differs being that the dish model is the nested resource that's being voted upon.
I tried translating the provided code but to no avail. At this point should I create a new controller for dishes and place the votable actions there? If so how would I setup my route so I can accomplish this on my restaurant's show page?
Models
class Restaurant < ActiveRecord::Base
has_many :dish_categories, dependent: :destroy
has_many :dishes, through: :dish_categories
end
class DishCategory < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes, dependent: :destroy
delegate :name, to: :dish_category, prefix: "category"
delegate :restaurant, to: :dish_category
end
class Dish < ActiveRecord::Base
belongs_to :dish_category
end
Restaurants Controller
...
def upvote
#restaurant = Restaurant.find(params[:id])
#dish = Dish.find(params[:id])
#dish.liked_by current_user
redirect_to #restaurant
end
def downvote
#restaurant = Restaurant.find(params[:id])
#dish = Dish.find(params[:id])
#dish.disliked_by current_user
redirect_to #restaurant
end
...
Routes
resources :restaurants do
member do
put "upvote", to: "restaurants#upvote"
put "downvote", to: "restaurants#downvote"
end
end
Restaurants - Show View
...
<% #restaurant.dishes.each do |dish| %>
<div>
<h2><%= dish.category_name %></h2>
<b><%= dish.name %></b>
<%= link_to "Upvote", like_restaurant_path(dish), method: :put %>
<%= link_to "Downvote", dislike_restaurant_path(dish), method: :put %>
</div>
<% end %>
A number of things needed to be done to get this to work. The first order of business was moving my controller action to my dishes controller. I also added two more actions: unlike and undislike for toggle functionailty.
NOTE: Logic for authenticating non-registered for users to liking/disliking dishes would still need to be written but this should help get you started.
Dishes Controller
class DishesController < ApplicationController
before_action :load_restaurant_and_dish, only: [:like, :unlike, :dislike, :undislike]
def like
#dish.liked_by current_user
redirect_to #restaurant
end
def unlike
#dish.unliked_by current_user
redirect_to #restaurant
end
def dislike
#dish.disliked_by current_user
redirect_to #restaurant
end
def undislike
#dish.undisliked_by current_user
redirect_to #restaurant
end
private
def load_restaurant_and_dish
#dish = Dish.find(params[:id])
#restaurant = #dish.restaurant
end
end
Next was configuring my routes to correspond with my restaurant and dish models:
Routes
resources :restaurants do
resources :dishes, only: [:like, :unlike, :dislike, :undislike] do
member do
put "like", to: "dishes#like"
put "unlike", to: "dishes#unlike"
put "dislike", to: "dishes#dislike"
put "undislike", to: "dishes#undislike"
end
end
end
I ended up refactoring my show view and created a few partials to reduce clutter now that there's a little bit of logic involved:
Restaurants - Show View
...
<%= render "restaurants/dish_partials/dishes" %>
...
Dishes Partial
<% #dishes.each do |dish| %>
<div>
<h2><%= dish.category_name %></h2>
<span><b><%= dish.name %></b></span>
<%= render "restaurants/dish_partials/like_toggle", dish: dish %>
</div>
<% end %>
Like Toggle Partial
<% if current_user.liked? dish %>
<%= link_to "Unlike", unlike_restaurant_dish_path(#restaurant, dish), method: :put %>
<% else %>
<%= link_to "Like", like_restaurant_dish_path(#restaurant, dish), method: :put %>
<% end %>
<% if current_user.disliked? dish %>
<%= link_to "Undislike", undislike_restaurant_dish_path(#restaurant, dish), method: :put %>
<% else %>
<%= link_to "Dislike", dislike_restaurant_dish_path(#restaurant, dish), method: :put %>
<% end %>

Resources