Rails - routing to a parent show page with a child_id - ruby-on-rails

I would like to route to the parent (journal) show page after deleting the child (habit) using the child_id.
In my app, a User can create journals, which then have multiple habits. I would like to be able to delete (and edit) a habit and then return to the journal show page, which displays all of the habits.
Getting the following and similar errors:
ActiveRecord::RecordNotFound in HabitsController#destroy
journal.rb
class Journal < ApplicationRecord
has_many :entries
has_many :habits
belongs_to :user
end
habit.rb
class Habit < ApplicationRecord
belongs_to :journal
has_many :completed_dates
end
show.html.erb
<h3>Habits</h3>
<% #journal.habits.each do |habit| %>
<div iv class="habit-list">
<div class="habit-name"><%= habit.name %></div>
<div class="habit-status">
<%= simple_form_for [#journal, #habit] do |f| %>
<%= f.input :status, label: false, :inline_label => true %>
<% end %>
</div>
<div>
<%= link_to habit_path(habit), method: :delete do %>
<i class="fas fa-trash btn-edit"></i>
<% end %>
</div>
</div>
<% end %>
habits_controller.rb
class HabitsController < ApplicationController
before_action :set_journal, only: [:new, :create, :edit, :update, :destroy]
before_action :set_habit, only: [:show, :edit, :update, :destroy]
def index
#habits = Habit.all.sort_by &:name
end
def new
#habit = Habit.new
end
def show
end
def create
#habit = #journal.habits.new(habit_params)
if #habit.save
redirect_to journal_path(#journal)
else
render :new
end
end
def edit
end
def update
if #journal.habits.update(habit_params)
redirect_to journals_path(#journal)
else
render :edit
end
end
def destroy
#habit.destroy
redirect_to journal_path(#habit, #journal)
end
private
def habit_params
params.require(:habit).permit(:name, :status, :user_id, :journal_id)
end
def set_journal
#journal = Journal.find(params[:journal_id])
end
def set_habit
#habit = Habit.find(params[:id])
end
end

Your trying to create URL to a deleted resource (#habit).
Change
def destroy
#habit.destroy
redirect_to journal_path(#habit, #journal)
end
to
def destroy
#habit.destroy
redirect_to journal_path(#journal)
end

Related

Clicking on a Username of another user links to my profile instead of the user's profile

I need help with this my code,that displays list of posts of users along with their username.What i want is, when i click on a username of a particular post, it should send me to that user's profile. instead, it send's to my own profile or the current user's profile whiles i want it to link me to the username i have clicked profile. (e.g like when you click on a username on Instagram, it links you to the user's profile so you can follow or unfollow and see their post)
Please i need help. what i'm i not doing right in my code.
i'm on rails 5.2.3 & ruby 2.3.3
Home
<div class="posts">
<% #posts.each do |post| %>
<section class="post">
<div class="user">
<div class="avatar">
<img src="assets/avater.jpg">
</div>
<%= link_to post.user.username, user_path(post.user), class: 'username' %>
</div>
<%= image_tag post.image, class: 'main-image' %>
<div class="description">
<% post.description.to_s.split(' ').each do |word| %>
<% if word.start_with?('#') %>
<%= link_to word, search_index_path(query: word) %>
<% else %>
<%= word %>
<% end %>
<% end %>
</div>
</section>
<% end %>
<%= paginate #posts %>
</div>
routes
Rails.application.routes.draw do
get 'search/index'
devise_for :users
get 'home/index'
resources :posts
root 'home#index'
resources :users, only: [:show, :edit, :update]
resources :posts, only: [:new, :create, :show, :destroy]
end
users controller
class UsersController < ApplicationController
before_action :find_user
def show
#user = User.find(params[:id])
#posts = current_user.posts.order(created_at: :desc)
end
def edit
end
def update
current_user.update(user_params)
redirect_to current_user
end
private
def find_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:username, :name, :website,:bio, :email, :phone, :gender, :avatar)
end
end
post controller
class PostsController < ApplicationController
def new
#post = current_user.posts.build
end
def create
#post = Post.create(post_params)
redirect_to root_path
end
def show
#post = Post.find(params[:id])
end
def destroy
#post = current_user.posts.find(params[:id])
#post.destroy
redirect_to user_path(current_user)
end
private
def post_params
params.require(:post).permit(:description, :image, :user_id)
end
end
home controller
class HomeController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.order(created_at: :desc).page(params[:page]).per(5)
end
end
I guess the problem is that on the show method from users_controller, you are getting the posts from current_user instead of the user, it should be #posts = #user.posts.order(created_at: :desc)

how to make my created award object become assigned to a car object?

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

how to access child new form from parent index page in rails?

I am trying to fetch booking controller's new form, from the cab index page. how can i fetch it? how can access the new form from cab index page where i have shown all the cabs which are added..
cab controller
class CabsController < ApplicationController
before_action :find_cab, only: [:show, :edit, :update, :destroy]
def index
#cabs = Cab.all.order("created_at DESC")
end
def new
#cab = Cab.new
end
def show
#reviews = Review.where(cab_id: #cab.id).order("created_at DESC")
if #reviews.blank?
#avg_review=0
else
#avg_review=#reviews.average(:rating).round(2)
end
end
def edit
end
def create
#cab = Cab.new(cab_params)
if #cab.save
redirect_to #cab
else
render 'new'
end
end
def update
if #cab.update(cab_params)
redirect_to #cab
else
render 'edit'
end
end
def destroy
#cab.destroy
redirect_to root_path
end
private
def find_cab
#cab = Cab.find(params[:id])
end
def cab_params
params.require(:cab).permit(:name, :number_plate, :seat, :image)
end
end
booking controller
class BookingsController < ApplicationController
before_action :find_booking, only: [:show, :edit, :update, :destroy]
before_action :find_cab
def index
#bookings = Booking.where(cab_id: #cab.id).order("created_at DESC")
end
def new
#booking = Booking.new
end
def show
end
def edit
end
def create
#booking = Booking.new(booking_params)
#booking.user_id = current_user.id
#booking.cab_id = #cab.id
if #booking.save
redirect_to cab_booking_path(#cab, #booking)
else
render 'new'
end
end
def update
end
def destroy
end
private
def find_booking
#booking = Booking.find(params[:id])
end
def find_cab
#cab = Cab.find(params[:cab_id])
end
def booking_params
params.require(:booking).permit(:date, :address, :start_destination, :destination, :start_date, :end_date, :contact_no)
end
end
routes
resources :cabs do
resources :bookings
end
cab/index.html.erb
<div class="container">
<h2>All Cabs</h2>
<div class="row">
<% #cabs.each do |cab| %>
<div class="col-sm-6 col-md-3">
<div class="thumbnail">
<%= link_to image_tag(cab.image.url(:medium), class: 'image'), cab %><br>
Cab Name : <h4><%= cab.name %></h4>
<%= link_to "Book Now", new_cab_booking_path(#cab, #booking) %> # i wanted to create this link
</div>
</div>
<% end %>
</div>
<%= link_to "Add Cab", new_cab_path, class: 'btn btn-default' %>
the error i am getting is
No route matches {:action=>"new", :cab_id=>nil, :controller=>"bookings"} missing required keys: [:cab_id]
No route matches {:action=>"new", :cab_id=>nil,
:controller=>"bookings"} missing required keys: [:cab_id]
The problem is with this line
<%= link_to "Book Now", new_cab_booking_path(#cab, #booking) %>
which should be
<%= link_to "Book Now", new_cab_booking_path(cab) %>

Rails user rating, can only rate myself

I am trying to set up a 5 star rating system so users can rate other users. At the moment everything is working, (create, delete, update etc...) but only the logged in user can rate himself. I cannot rate other users. I get no errors, it just redirects to the user profile page as it should but without added a rating to that user.
user.rb
class User < ActiveRecord::Base
has_many :reviews
review.rb
class Review < ActiveRecord::Base
belongs_to :user
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :find_user
before_action :find_review, only: [:edit, :update, :destroy]
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
if #review.save
redirect_to user_path(#user)
else
render 'new'
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to user_path(#user)
else
render 'edit'
end
end
def destroy
#review.destroy
redirect_to user_path(#user)
end
private
def review_params
params.require(:review).permit(:rating, :comment)
end
def find_user
#user = User.find(params[:user_id])
end
def find_review
#review = Review.find(params[:id])
end
end
_form which then gets rendered on show page:
<%= simple_form_for([#user, #user.reviews.build]) do |f| %>
<div id="rating-form">
<label>Rating</label>
</div>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
<script>
$('#rating-form').raty({
path: '/assets/',
scoreName: 'review[rating]'
});
</script>
Any help getting this to work would be greatly appreciated!!
Do this:
#config/routes.rb
resources :users do
resources :reviews, only: [:new, :create]
end
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :reviewed, class_name: "User", foreign_key: :reviewed_id
end
#app/controllers/reviews_controller.rb
class ReviewsController < ApplicationController
def new
#review = current_user.reviews.new
end
def create
#review = current_user.reviews.new review_params
#review.save
end
private
def review_params
params.require(:review).permit(:rating, :comment).merge(reviewed_id: params[:user_id])
end
end
#app/views/reviews/new.html.erb
<%= form_for #review do |f| %>
<%= f.number_field :rating %>
<%= f.text_field :comment %>
<%= f.submit %>
<% end %>
This would mean you'll have to include a reviewed_id column in your reviews table.
You'll be able to access it using: url.com/users/:user_id/reviews/new
The application will automatically fill the user_id and reviewed_id fields, so the rest of your code should work with the upgrade.
The big problem you have is that you're basically recording the user_id (presumably of who created the review)... but have no way of stipulating who the review is about.
The above code fixes that for you.

Trying to add a partial form to my index page. How do I pass multiple variables to generate the form?

I have an index page of art that I vote on with ratings model. I can vote on the show page but I want it to be able to vote on the index page also. The form for the ratings has three variables. How should the Art Controller index page look and the code for the index html page. I'm getting an error that "rating" is undefined. Please help, this is like the last hurdle I got to get over to complete this project.
**Update: I changed my routes so the form only has two variables now. But still having trouble rendering the form on the index page.
Routes to a new rating
new_art_rating GET /arts/:art_id/ratings/new(.:format)
Routes.rb
resources :campaigns do
resources :lyrics do
member do
get "like", to: "lyrics#upvote"
get "dislike", to: "lyrics#downvote"
end
resources :comments
end
resources :arts do
member do
get "like", to: "arts#upvote"
get "dislike", to: "arts#downvote"
end
resources :commentarts
end
end
resources :arts do
resources :ratings
end
Art Index
<% #arts.each do |art| %>
<div class="container-md">
<%= render partial: 'ratings/form', :locals =>{:campaign => #campaign, :art => #art, :rating => #art.rating} %>
<%= link_to campaign_art_path(#campaign, art) do %>
<%= image_tag art.image.url(:small) %>
<% end %>
Arts Controller
class ArtsController < ApplicationController
before_action :tag_cloud, :only => [:index]
load_and_authorize_resource :only => [:show, :edit, :update, :destroy]
before_action :find_post, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :set_campaign
before_action :authenticate_user!, except: [:index, :show]
impressionist :actions=>[:show,:index], :unique => [:impressionable_type, :impressionable_id, :session_hash]
def index
#arts = Art.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 10)
#rating = Rating.new
end
def show
#commentarts = Commentart.where(art_id: #art)
#ratings = Rating.where(art_id: #art)
#random_art = Art.where.not(id: #art).order("RANDOM()").first
end
def new
#art = Art.new
end
def create
#art = Art.new(post_params)
#art.user_id = current_user.id
#art.campaign_id = #campaign.id
if #art.save
redirect_to([#art.campaign, #art])
else
render 'new'
end
end
def edit
end
def update
if #art.update(post_params)
redirect_to([#art.campaign, #art])
else
render 'edit'
end
end
def destroy
#art.destroy
redirect_to root_path
end
def upvote
#art.upvote_by current_user
redirect_to([#art.campaign, #art])
end
def downvote
#art.downvote_by current_user
redirect_to([#art.campaign, #art])
end
def tagged
if params[:tag].present?
#arts = Art.tagged_with(params[:tag]).order("created_at desc")
else
#arts = Art.all.order("created_at desc")
end
end
def tag_cloud
#tags = Art.tag_counts_on(:tags)
end
private
def find_post
#art = Art.find(params[:id])
end
def set_campaign
#campaign = Campaign.find(params[:campaign_id])
end
def post_params
params.require(:art).permit( :image, :description, :artist, :typeart, :link)
end
end
Ratings Controller
class RatingsController < ApplicationController
before_action :authenticate_user!
def create
#art = Art.find(params[:art_id])
#rating = Rating.create(params[:rating].permit(:rate))
#rating.user_id = current_user.id
#rating.art_id = #art.id
if #rating.save
redirect_to([#art.campaign, #art])
else
render 'new'
end
end
end
Form view
<%= simple_form_for([#art, #art.ratings.build]) do |f| %>
<%= f.error_notification %>
<div class="field">
<div id="star-rating"></div>
</div>
<%= f.button :submit, "Rate", class: "button" %>
<% end %>
<script>
$('#star-rating').raty({
path: '/assets/',
scoreName: 'rating[rate]'
});
</script>
Campaign Controller
class CampaignsController < ApplicationController
before_action :find_campaign, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
has_scope :free
has_scope :open
has_scope :closed
def index
#campaigns = Campaign.all.order("created_at DESC")
#free_campaign = Campaign.free.first
#open_campaigns = Campaign.open.all
#closed_campaigns = Campaign.closed.all
end
def show
#lyrics = Lyric.where(campaign_id: #campaign.id).order("created_at DESC")
#arts = Art.where(campaign_id: #campaign.id).order("created_at DESC")
#time = Time.now
end
def new
#campaign = current_user.campaigns.build
end
def create
#campaign = current_user.campaigns.build(campaign_params)
if #campaign.save
redirect_to #campaign
else
render 'new'
end
end
def edit
end
def update
if #campaign.update(campaign_params)
redirect_to #campaign
else
render 'edit'
end
end
def destroy
#campaign.destroy
redirect_to root_path
end
private
def find_campaign
#campaign = Campaign.find(params[:id])
end
def campaign_params
params.require(:campaign).permit(:title, :description, :timer, :timer2, :image, :status)
end
end
Error Message is in the Arts#index. Undefined method ratings. First line in my form.
NoMethodError in Arts#index undefined method `ratings' for nil:NilClass
Extracted source (around line #1):
**<%= simple_form_for([#art, #art.ratings.build]) do |f| %>**
<%= f.error_notification %>
<div class="field">
<div id="star-rating"></div>
Presumably Arts index has multiple Art instances, so there is not '#art'.
<% #arts.each do |art| %>
<%= simple_form_for([art, art.ratings.build]) do |f| %>
Etc. Or if there really is only one Art displayed on index, then instantiate that in the controller.
Perhaps also edit this line? I need to see the error log to see where you're seeing the error.
Rating.create(params[:rating].permit(:rate))
I'd break that out into a separate method:
Rating.create(rating_params[:rate))
def rating_params
params.require(:rating).permit(:rate)
end
And I'd check what the javascript 'raty' library is actually inserting into the DOM and whether it really is sending the params you think it is?

Resources