Updating attributes from check_box - ruby-on-rails

I'm using nested models in my first Ruby on Rails app and now I've run into a problem. I have a Survey model that has_many :questions which in turn belongs_to :survey and the model Question has_many :answers. My Answer model then belongs_to :question.
Now I want to update a boolean attribute :guess within my :answers controller. To this end I've created a new action :quiz_guess which looks like this:
def quiz_guess
Answer.update(params[:id], guess: false)
puts("Guess saved")
redirect_to(:action => 'show', :id => #survey.next, :survey_id => #survey.id)
end
my view looks like this:
<%= form_tag quiz_guess_questions_path, :method => :put do %>
<% for question in #survey.questions do %>
<li><%= h question.content %></li>
<% for answer in question.answers do %>
<li><%= h answer.content %>
<%= form_for :guess do |f| %>
<%= f.check_box(:guess, :method => :put) %>
<% end %>
</li>
<% end %>
<% end %>
<% end %>
Obviously I've read the documentation, as well as this blog post, but I don't understand how to implement it in my controller and view.
With this code I'm not able to update the correct :guess attribute but rather I update a different one (with a different :id). Can anybody shed some light as to what I do wrong?

I ended up looking at this Railscast where Ryan Bates shows how to update multiple attributes with fields_for. This is my new view:
<%= form_tag quiz_guess_questions_path, :method => :put do %>
<% for question in #survey.questions do %>
<li><%= question.content %></li>
<% for answer in question.answers do %>
<li>
<%= fields_for "answers[]", answer do |f| %>
<%= answer.content %>
<%= f.check_box :guess %>
<% end %>
</li>
<% end %>
<% end %>
<%= submit_tag "Guess" %>
<% end %>
and my new controller:
def quiz_guess
Answer.update(params[:answers].keys, params[:answers].values)
flash[:notice] = "Guess saved successfully."
redirect_to questions_url
end

Related

undefined method `comments_path' for #<#<Class:... > (RAILS)

I'm trying to add comments to my photos model however when I submit my comment I am getting the following error:
undefined method `comments_path' for #<#<Class:0x007fdef11c3dd8>:0x007fdef4163f98>
My routes look like this:
resources :photos do
resources :comments
end
Models:
class Comment < ActiveRecord::Base
belongs_to :photo
end
class Photo < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
end
views new comment:
<%= form_for [#picture, #comment] do |f| %>
<%= f.label :comments %>
<%= f.text_area :comments %>
<%= f.submit 'Leave Comment' %>
<% end %>
views index:
<% if #photos.any? %>
<% #photos.each do |photo| %>
<%= link_to photo.title, photo_path(photo) %>
<%= photo.description %>
<% if photo.comments.any? %>
<ul>
<% photo.comments.each do |comment| %>
<li>
<%= comment.comments %>
</li>
<% end %>
<% else %>
<p> No comments yet </p>
<% end %>
<% if current_user %>
<%= link_to "Comment on #{photo.title}", new_photo_comment_path(photo) %>
<% if current_user.id == photo.user_id %>
<%= link_to "Delete #{photo.title}", photo_path(photo), method: :delete %>
<% end %>
<% end %>
<br>
<% end %>
<% else %>
No photos yet
<% end %>
<br>
<%= link_to "Add a photo", new_photo_path %>
Comments Controller:
class CommentsController < ApplicationController
def new
#photo = Photo.find(params[:photo_id])
#comment = Comment.new
end
def create
#photo = Photo.find(params[:photo_id])
#photo.comments.create(comment_params)
redirect_to photos_path
end
def review_params
params.require(:comment).permit(:comments)
end
end
Please let me know if you need any further info, haven't posted much so still getting used to the format. Thanks all.
EDIT: Here is the error I am getting in full:
Error message
Problem was in the comments view:
<%= form_for [#picture, #comment] do |f| %>
<%= f.label :comments %>
<%= f.text_area :comments %>
<%= f.submit 'Leave Comment' %>
<% end %>
#picture was meant to be #photo. doh.

Refactoring into partials in Rails

In page1, I use code A+B+C
In page2, I use code B+C
So when I make a partial, I realy have no idea in how to deal with this.
For example, In a Post-Comment system. I want to show #comments in 2 different pages. In the comment index page,
We show the post it belongs to. And in the post show page, We only have to show the comments content.(Since there is no need to show the comment.post again)
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= comment.author %>
<%= comment.content %>
<% end %>
..
#Post Show Page
<% #comments.each do |comment| %>
<%= comment.author %>
<%= comment.content %>
<% end %>
So, how do I make a partial to reuse the code? Perhaps like this? But this there more elegant way of doing this?
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= render comment %>
<% end %>
#Post Show Page
<% #comments.each do |comment| %>
<%= render comment %>
<% end %>
Updated:
I adopt the local variable approach, and update my code like:
# partial
<% if include_topic %>
<div class="Topic">
<h5><%= link_to "#{comment.topic.content}", comment.topic %></h5>
</div>
<% end %>
#Index
<%= render #comments, :locals => {:include_topic => true } %>
But I get undefined local variable or method `include_topic' for #<#
I just find nowhere to debug this issue
Your partial:
<%= comment.post if include_post %>
<%= comment.author %>
<%= comment.content %>
your code:
#index page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => true } %>
#show page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => false } %>
Syntax could be much shorter but it depends whether or not you stick to rails conventions see doc.
Sidenote: I don't like 1.8.7 syntax
In the partial,
<% comments.each do |comment| %>
<%= comment.post if params[:controller] == "comments" %>
<%= comment.author %>
<%= comment.content %>
<% end %>
and now render this partial in both comments/index and posts/show pages by specifying the comments as a local variable.

How does an :as association work?

My comments model is pretty simple and works polymorphically, but I am now adding the ability to hide a comment by the author of a given record across those polymorphic associations.
class Comment < ActiveRecord::Base
attr_accessible :content, :show
belongs_to :commentable, :polymorphic => true
belongs_to :user
end
So, requests, questions, posts, submissions etc... all have comments and are accessing the comments template without issue, but I want to allow the author of the content in those models to show or hide comments (as opposed to flagging, for example) when the application identifies them as the author of the content that is being commented on.
class Request < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy
end
So, I have everything working when there is only one model, by calling the author: #request.user,
but I'm wondering how to call an author using metaprogramming, so the comment view (with help) can determine what model is currently using the comment view.
I've done some research into metaprogramming, but have not found the answer.
Here is the code that calls the author (#request.user):
<% if #comments %>
<h1 class="mtop20">Comments</h1>
<% for comment in #comments %>
<% if signed_in? %>
<% if comment.show == true %>
<div class="well comment mtop10">
<% if current_user == #request.user or current_user.has_role? :admin %>
<%= simple_form_for [#commentable, comment] do |f| %>
<div class ="">
<%= f.input :show, :as => :hidden, :input_html => { :value => false } %>
<%= f.submit "Hide Comment", :class => 'btn btn-mini pull-right' %>
</div>
<% end %>
<% end %>
<span>
<%= image_tag comment.user.image.source(:header) %>
<%= link_to comment.user.name, comment.user %></span>
Posted <%= time_ago_in_words(comment.created_at) %> ago
</span>
<p class="mleft20 mtop10"><%= comment.content %></p>
<% if signed_in? %>
<% if current_user.id == comment.user_id or current_user.has_role? :admin %>
<%= link_to 'Edit', polymorphic_path([ comment.commentable, comment], :action => :edit),
:class => 'btn btn-mini mtop5 mleft10' %>
<%= link_to 'Delete', [comment.commentable, comment],
:confirm => 'Are you sure?',
method: :delete,
:class => 'btn btn-mini mtop5' %>
<% end %>
<% end %>
</div>
<% end %>
<% if comment.show == false %>
<p>A comment by <%= comment.user.name %> has been hidden by <%= #request.user.name %></p>
<% if current_user == #request.user or current_user.has_role? :admin %>
<%= simple_form_for [#commentable, comment] do |f| %>
<div class ="">
<%= f.input :show, :as => :hidden, :input_html => { :value => true } %>
<%= f.submit "Show Comment", :class => 'btn btn-mini btn-success' %>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= render "comments/form" %>
use comment.commentable.user to access the author of your post.

How to have a polymorphic model's partials associate to different things on the same page

Essentially, I have a binary voting system Like/Dislike. Thee class is called Like It has polymorphic associations to likeable:
class Like < ActiveRecord::Base
belongs_to :likeable, polymorphic: true
end
and we have the class Comment, which also has polymorphic associations to commentable and can be liked
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
has_many :likes, :as :likeable
end
We have the class Section, which can also be liked and commented on
class Section < ActiveRecord::Base
has_many :likes, as: :likeable
has_many :comments, as: commentable
end
However, on the page section#show I display the Section information, the section likes, and then the comments (from a comments/comments partial). Here is the Section#show view:
<h1><%= exercise.name %></h1>
<p><%= exercise.description %></p>
<%= render 'likes/like_button' %>
<%= render 'comments/comments' %>
<%= render 'comments/comment_form' %>
However, I want the ability to vote on each comment.
The following code is from the _comments.html.erb - What currently doesn't work is the rendering of the _like_button.html.erb because it doesn't apply to the comment at hand.
<% #comments.each do |comment| %>
<%= comment.content %>
<%= render 'likes/like_button' %>
<hr />
<% end %>
And here is the _like_button.html.erb partial
<% if #like.nil? %>
<%# No record of Like in table %>
<%= form_for [#likeable, Like.new] do |f| %>
<%= f.submit "Like" %>
<%= f.submit "Dislike" %>
<% end %>
<% else %>
<%# Marks current chosen option, if the opposite option is chosen, the record is updated to reflect the descion by the user %>
<%= form_for [#likeable, #like] do |f| %>
<% if #like.is_liked %>
Currently Liked!
<%= f.submit "Dislike" %>
<% else %>
<%= f.submit "Like" %>
Currently Disliked!
<% end %>
<% end %>
<% end %>
So ultimately, I just want to know how to make it possible to vote on a comment from within the Section#show view
Thanks!
Try this:
<% #comments.each do |comment| %>
<%= comment.content %>
<%= render 'likes/like_button', :like => comment.like, :likeable => comment %>
<hr />
<% end %>
<% if like.nil? %>
<%# No record of Like in table %>
<%= form_for [likeable, Like.new] do |f| %>
<%= f.submit "Like" %>
<%= f.submit "Dislike" %>
<% end %>
<% else %>
<%# Marks current chosen option, if the opposite option is chosen, the record is updated to reflect the descion by the user %>
<%= form_for [likeable, like] do |f| %>
<% if like.is_liked %>
Currently Liked!
<%= f.submit "Dislike" %>
<% else %>
<%= f.submit "Like" %>
Currently Disliked!
<% end %>
<% end %>
<% end %>

Rails Geocoder - Still learning

I'm sure it's a simply issue due to me not fully understanding how bits fit together in Rails...
I've followed the rails cast but I'm having trouble implementing it into my app (I've had it working stand-alone).
The error I get is
undefined method `nearbys'
Here's what I've got:
user.rb
geocoded_by :full_address
after_validation :geocode
def full_address
[address1, address2, address3, city, country, postcode].compact.join(', ')
end
users_controller.rb
def index
#title = "All users"
if params[:search].present?
#users = User.near(params[:search], 50, :order => :distance)
else
#users = User.all
end
end
index.html.erb
<h3>Nearby locations</h3>
<ul>
<% for user in #users.nearbys(10) %>
<li><%= link_to user.address1, user %> (<%= user.distance.round(2) %> miles)</li>
<% end %>
</ul>
_sidebar.html.erb
<%= form_tag users_path, :method => :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search Near", :name => nil %>
</p>
<% end %>
Thanks
If I comment out the .nearbys
<% for user in #users#.nearbys(10) %>
<li><%= link_to user.latitude, user %> (<%= user.distance.round(2) %> miles)</li>
<% end %>
The search works. Could this be a problem with the install of geocoder?
The function nearbys is a function on your model, not on a collection of models. The variable #users contains a collection of User models. You need to call the function on a single model instance, for example for each user in #users.
As an example, but not sure if you really want this:
<% #users.each do |user| %>
<% user.nearbys(10).each do |near_user| %>
<li><%= link_to near_user.latitude, near_user %> (<%= near_user.distance.round(2) %> miles)</li>
<% end %>
<% end %>
(Note that I also changed the for user in #users to use #users.each do |user|, which is more "Rubyish".)

Resources