I am trying to access an "edit" link to edit an object, but I'm getting this error:
Param is missing or the value is empty: preview
Basically, I have 2 models that I linked through association:
Game model
Review model
I'm rendering reviews in the Game's show page. When I try to edit a review, it's saying I'm missing params or the value is empty in the Reviews controller.
The routes are also nested. How can I fix this?
Thanks in advance :)
routes.rb
Rails.application.routes.draw do
devise_for :users
root "games#index"
resources :games do
resources :news
resources :reviews, except: [:show, :index]
resources :previews, except: [:show, :index]
end
resources :platforms
resources :genres
end
show.html.erb (Linked to Games controller)
<% if #news.last.created_at > preview.updated_at %>
<p><%= link_to "edit", edit_game_preview_path(#game.id, preview.id) %></p>
<% end %>
<p><%= link_to "delete", game_preview_path(#game.id, preview.id), method: :delete %></p>
<% end %>
Reviews partial (Form)
<%= form_for [#game, #previews.new] do |r| %>
<h3 class="post_review">Preview this game</h3>
<p><%= flash[:notice_submit] %></p>
<p><%= r.text_field :title, placeholder: "Enter your tagline" %></p>
<p><%= r.text_area :content, placeholder: "Enter your review here" %></p>
<p><%= r.text_area :vote %></p>
<p><%= r.hidden_field :game_id, value: #game.id %></p>
<%= r.submit %>
<% end %>
Reviews controller
class PreviewsController < ApplicationController
before_action :authenticate_user!
before_action :set_preview, only: [:show, :edit, :update, :destroy]
before_action :set_game
def new
#preview = Preview.new
end
def create
#preview = Preview.new(preview_params)
#preview.user_id = current_user.id
#preview.game_id = #game.id
#preview.username = current_user.username
if #preview.save
redirect_to :back
flash[:notice_submit] = "Thanks for you comment!"
else
redirect_to :back
flash[:notice_submit] = "Either you've already voted, or you're not filling in all forms."
end
end
def edit
#preview.update(preview_params)
redirect_to #game
end
def destroy
#preview.destroy
redirect_to #game
end
private
def set_preview
#preview = Preview.find(params[:id])
end
def set_game
#game = Game.find(params[:game_id])
end
def set_user
#user = User.find(params[:user_id])
end
def preview_params
params.require(:preview).permit(:title, :content, :vote)
end
end
You are getting this error because in your preview_params you are requiring a preview object.
I think your controller logic for the edit action is invalid. For the edit action, you just need to set_preview and then render the edit template. The current logic in your edit action should go in an update action.
def edit
end
def update
#preview.update(preview_params)
redirect_to #game
end
Also the first line of your form should be:
<%= form_for [#game, #preview] do |r| %>
Related
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)
Not sure why comments created on _comment_form.html.erb is not being rendered on articles/:id
I'm referencing this youtube tutorial: https://www.youtube.com/watch?v=IUUThhcGtzc
Comments controller:
class CommentsController < ApplicationController
before_action :authenticate_user!
before_action :set_article
def create
#comment = #article.comments.create(params[:comment].permit(:content, :article_id, :user_id))
#comment.user = current_user
#comment.save
if #comment.save
redirect_to #article
else
redirect_to #article
end
end
private
def set_article
#article = Article.find(params[:article_id])
end
end
Articles controller:
class ArticlesController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_article, only: [:show, :edit, :update, :destroy]
def show
#comments = Comment.where(article_id: #article).order("created_at DESC")
end
private
def set_article
#article = Article.find(params[:id])
end
end
_comment.html.erb (from articles/show.html.erb)
<%= render 'comments/comment_form' %>
<% #comments.each do |comment| %>
<%= comment.content %>
<% end %>
_comment_form.html.erb
<% if user_signed_in? %>
<%= form_for ([#article, #article.comments.build]) do |f| %>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: 'form-control' %>
</div>
<%= f.submit 'Post Comment', class: 'btn btn-primary' %>
<% end %>
<% end %>
routes.rb
resources :articles do
resources :comments
end
Some considerations I would like to do:
#comment.save
if #comment.save
When you do that, you're saving twice. Calling #comment.save on if condition already saves the article and return true or false if it was successful. Also, replace .save for .save!, so it will raise an exception in case it doesn't save, so you can check the reason on rails server log.
Also, think it's unnecessary to do this:
#comments = Comment.where(article_id: #article).order("created_at DESC")
Since you already set the #article, you can access #article.comments, once you put has_many :comments on article model.
You can also check on rails console if the Article was created correctly. Create a new one, and get it like article = Article.last, then you can check article.comments.
Hope this helps!
Right now i am finishing my small learning project but I am sturggling with one thing. The funcionalities of the project are: register, login, logout for the Author; creating, editing, removing of the Events; attend, un-attend event.
Last thing what I want to implement is, to be able to see who is attending certain event. The functionality of attending / un-attending is already done (made a table Eventattendences with references to events and author).
The only thing which is missing is showing WHO is attending different event (that means to show Authors_key from the eventattendances table where events_id is equal in my show.html.erb). When i am trying to do that i always get an empty object from the SHOW method of eventattendacnes_controller.
Adding here all the code that should be related to this (if anything is missing just let me know and I will add it here). THANK YOU!
Versions: Rails(4.0.0), Ruby(2.3.3p222)
eventattendances_controller
class EventattendancesController < ApplicationController
before_action only: [:show, :edit, :update, :destroy]
before_filter :require_login
def new
if Eventattendance.exists?(events_id: params[:event_id].to_i, authors_id: current_user.id)
redirect_to event_path(params[:event_id])
else
#eventattendance = Eventattendance.new(events_id: params[:event_id].to_i, authors_id: current_user.id)
#eventattendance.save
redirect_to event_path(params[:event_id])
end
end
def destroy
if Eventattendance.exists?(events_id: params[:event_id].to_i, authors_id: current_user.id)
Eventattendance.where(events_id: params[:event_id].to_i, authors_id: current_user.id).first.destroy
redirect_to event_path(params[:event_id])
else
redirect_to event_path(params[:event_id])
end
end
def show
#eventattendances = Eventattendance.find(events_id= params[:event_id].to_i)
end
private
def author_params
params.require(:author).permit(:username, :email, :password,:password_confirmation)
end
def event_params
params.require(:event).permit(:title, :body)
end
end
eventattendances.rb (Model)
class Eventattendance < ActiveRecord::Base
belongs_to :author
belongs_to :event
end
routes.rb
Events::Application.routes.draw do
root to: 'events#index'
resources :events
resources :authors
resources :author_sessions, only: [ :new, :create, :destroy ]
resources :eventattendances, only: [:destroy, :new, :show]
get 'login' => 'author_sessions#new'
get 'logout' => 'author_sessions#destroy'
end
views/events/show.html.erb (here i want to set the show function from eventattendances to show the authors_id of the authors that are attending the event)
`<h1><%= #event.title %></h1>
<p><%= #event.body %></p>
<%= #at_list.blank? %>
<%= #at_list_att.blank? %>
<%=sql = "Select * from eventattendances"
at_list = ActiveRecord::Base.connection.execute(sql) %>
<% #event.eventattendances.map do |eventattendance| %>
<tr>
<td><%= eventattendance.author_id %></td>
</tr>
<% end %>
<%= link_to "<< Back to Event List", events_path %>
<p> </p>
<br>
<% if logged_in? %>
<%= link_to "edit", edit_event_path(#event) %>
<%= link_to "delete", event_path(#event), method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
<%= link_to "Cancel atendance", eventattendance_path(event_id: #event.id), method: :delete, class: "btn btn-primary" %>
<%= link_to "Attend", new_eventattendance_path(event_id: #event.id), class: "btn btn-success"%>
`
events_controller
class EventsController < ApplicationController
include EventsHelper
before_filter :require_login, except: [:index]
def index
#events = Event.all
end
def show
#event = Event.find(params[:id])
end
def new
#event = Event.new
end
def create
#event = Event.new(event_params)
#event.save
redirect_to event_path(#event)
end
def destroy
#event = Event.find(params[:id])
#event.destroy
redirect_to events_path
end
def edit
#event = Event.find(params[:id])
end
def update
#event = Event.find(params[:id])
#event.update(event_params)
redirect_to event_path(#event)
end
private
def event_params
params.require(:event).permit(:title, :body)
end
end
author.rb
`class Author < ActiveRecord::Base
authenticates_with_sorcery!
validates_confirmation_of :password, message: "should match confirmation", if: :password
has_and_belongs_to_many :events
end`
event.rb
class Event < ApplicationRecord
has_and_belongs_to_many :authors
end
In first place, if you are rendering the views/events/show you could do
<% #event.eventattendances.map do |eventattendance| %>
<tr>
<td><%= eventattendance.author_id %></td>
</tr>
<% end %>
to get the author_id.
But thinking better, maybe you are having a problem of relations and you need a
has and belongs to many association
The solution was to put it into the show method of events_controller.rb (instead of eventattendances_controller)
#eventattendances = Eventattendance.find_by(events_id: params[:id])
+
to change the arguments of the find:
from (events_id= params[:event_id]) to (events_id: params[:id])
(maybe it is going to help someone in the future)
so I'm trying to create a video game review website for practice.
A game has many reviews, and votes. The idea is, in order to post a review, you must vote "Good" or "Bad" first, THEN submit a review. You can't post a text review without voting.
I'm trying to do this without the acts_as_voteable gem...
The data format for votes is boolean. "Good" is true, "Bad" is false.
How do I get the votes to save? below are my routes.rb, _review partial, reviews controller, and show page.
many thanks guys :)
edit****: also I'm trying to only one vote per user. I was thinking of using a token variable which equals to 1, and when a vote is cast, the token is -1. Is that a good approach? But the data type for vote is boolean, so how would that work -- or should I change the data type for vote from boolean to integer?
edit#2 -- so I added :vote into my params.
routes.rb
upvote_game_review_path
POST /games/:game_id/reviews/:id/upvote(.:format) reviews#upvote
downvote_game_review_path
POST /games/:game_id/reviews/:id/downvote(.:format) reviews#downvote
Rails.application.routes.draw do
devise_for :users
root "games#index"
resources :games do
resources :news
resources :reviews, except: [:show, :index] do
member do
post "upvote"
post "downvote"
end
end
end
resources :platforms
resources :genres
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :update, :edit, :destroy]
before_action :set_game
before_action :authenticate_user!
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.game_id = #game.id
if #review.save
redirect_to #game
else
render "review"
end
end
def upvote
#review.vote.create = true
redirect_to #game
end
def downvote
#review.vote.create
#review.vote = false
redirect_to #game
end
def edit
#review.update(review.params)
end
def destroy
#review.destroy
redirect_to #game
end
private
def set_review
#review = Review.find(params[:id])
end
def set_game
#game = Game.find(params[:game_id])
end
def review_params
params.require(:review).permit(:comment, :vote)
end
end
_review partial <-- to create a new review
<%= form_for [#game, #reviews.new] do |r| %>
<h3 class="post_review">Review this game</h3>
<p>
<%= r.text_area :comment %>
</p>
<p>
<%= button_to "Good", upvote_game_review_path(#game.id, r) %>
</p>
<p>
<%= button_to "Bad", downvote_game_review_path(#game.id, r) %>
</p>
<p>
<%= r.hidden_field :game_id, value: #game.id %>
<p>
<%= r.submit %>
<% end %>
show.html.erb
<p><%= link_to "<< Home", games_path %></p>
<span><%= link_to "Edit", edit_game_path(#game) %></span>
<span><%= link_to "Delete", game_path(#game), method: :delete %></span>
<div class="game_summary">
<h2><%= #game.title %></h2>
<%= image_tag #game.image %>
<p>Release Date: <%= #game.release_date %> </p>
<p>Genre: <%= #game.genre_id %> </p>
<p>Platforms: <%= #game.platform_id %></p>
</div>
<%= link_to "Add News", new_game_news_path(#game) %>
<h2>News & Articles</h2>
<%= link_to "view all", game_news_index_path(#game) %>
<% #news.each do |n| %>
<ol>
<li><%= link_to n.title, game_news_path(#game.id, n.id) %></li>
</ol>
<% end %>
<div class="game_review submit">
<%= render "review" %>
</div>
<% #reviews.each do |review| %>
<p><%= review.comment %></p>
<p><%= link_to "delete", game_review_path(#game.id, review.id), method: :delete %></p>
<% end %>
You don't specify which review you're loading in. The reason is here:
before_action :set_review, only: [:show, :update, :edit, :destroy]
You don't pull in the request's review instance when you go to either of those actions. Further, it doesn't look like you're actually saving them.
So, two things I'd recommend:
Add those methods to your before_action:
before_action :set_review, only: [:show, :update, :edit,
:destroy, :upvote, :downvote]
(May not be necessary, write tests to confirm this!) Actually save the entity after you've changed its value.
def upvote
#review.vote.create = true
#review.save
redirect_to #game
end
def downvote
#review.vote.create unless #review.vote
#review.vote = false
#review.save
redirect_to #game
end
I'm trying to add a flashcards(cardsets) feature in Rails and I'm having some problems implementing this as I'm getting an undefined methodcardsets' for nil:NilClass` error
I can get the page to render if I change: <% if #user.cardsets.any? %> to <% unless #cardsets.any? %> but the corresponding cardsets are being shown when I do this.
Here is the html.erb code that is producing this error:
<% provide(:title, "Flashcards") %>
<h1>Flashcards</h1>
<div class="row">
<aside class="span3">
<%= render "shared/cardset_form" %>
</aside>
<div class="span6">
**<% if #user.cardsets.any? %>**
<h3>Flashcard Sets (<%= #user.cardsets.count %>)</h3>
<ol class="cardsets">
<% #user.cardsets.each do |cardset| %>
<li>
<span class="topic"><%= link_to cardset.topic, show_cardset_path(cardset) %></span>
<%= link_to "edit", edit_cardset_path(cardset) %>
<%= render partial: "shared/delete_link", locals: {item: cardset} %>
</li>
<% end %>
</ol>
<% end %>
</div>
</div>
I've starred the line that is producing the undefined methodcardsets' for nil:NilClass` error.
This is what's in my cardsets_controller.rb:
class CardsetsController < ApplicationController
before_action :signed_in_user, only: [:new, :index, :create, :edit, :destroy, :update]
before_action :correct_user, only: [:edit, :update, :destroy]
def index
#cardsets = Cardset.all
end
def show
#cardset = Cardset.find(params[:id])
end
def create
#cardset = current_user.cardsets.build(cardset_params)
if #cardset.save
flash[:success] = "A new set of flashcards have been created!"
redirect_to #cardset
else
render "new"
end
end
def new
#cardset = Cardset.new
end
def edit
end
def update
#cardset = Cardset.find(params[:id])
if #cardset.update_attributes(cardset_params)
flash[:success] = "You've updated your flashcards!"
redirect_to #cardset
else
render "edit"
end
end
def destroy
#cardset = Cardset.find(params[:id])
#cardset.delete
redirect_to cardsets_path
end
private
def cardset_params
params.require(:cardset).permit(:topic, :description)
end
def correct_user
#cardset = current_user.cardsets.find_by_id(params[:id])
redirect_to root_url if #cardset.nil?
end
end
Here is the code in my cardset.rb file:
class Cardset < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :topic, presence: true
end
Here is the code in my user.rb file:
class User < ActiveRecord::Base
has_many :cardsets
(...a bunch of other code...)
end
If anyone could provide some help or suggestions on where I may be going wrong I'd greatly appreciate it!
Thanks!
As far as I can tell, you aren't setting #user in your Controller, so #user is nil.
You probably want to either define #user or maybe you meant to use #cardsets.