How does an :as association work? - ruby-on-rails

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.

Related

Rails check_box form to create has_many relationship

I have a model called account which has_many :options. I want to create a form in which i can list all the options with a checkbox at the side, so the current account can select the options he/she wants inside a form so I can create the has_many relation.
This is what i have
def index
#account = current_account
#options = ['Op 1', 'Op 2', 'Op 3', 'Op 4']
end
and for the view:
<%= form_for(#account, url: options_path) do |f| %>
<% #options.each do |op| %>
<div class="checkbox">
<%= f.check_box(?????, {:multiple => true}, op, nil) %>
</div>
<% end %>
<%= f.submit class: 'btn btn-default' %>
<% end %>
This is obviously not working and I'm pretty sure this is not the right way to achieve what I want to do, so any help would be appreciated.
You could use fields_for:
<%= form_for(#account, url: options_path) do |f| %>
<%= fields_for :options do |options_form| %>
<% #options.each do |option| %>
<div class='checkbox'>
<%= options_form.label option do %>
<%= options_form.check_box option %> <%= option %>
<% end %>
</div>
<% end %>
<% end %>
<%= f.submit class: 'btn btn-default' %>
<% end %>
And in your params, you will get values like: params[:account][:options]['Op1'] with value '1' for true and '0' for false.

Updating attributes from check_box

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

Rails: Pass ID of nested resource from button_to to controller / to toggle boolean in admin view

I am sitting here since the Dawn of Times trying to toggle a boolean in Rails for an admin to validate submissions.
I have a standard "Article" model, which has_many "Prosols" (which in turn belongs_to "Article").
A Prosol has a boolean "profeat1".
I am trying to toggle it thanks to a set of button_to (as follows).
I am looping through the articles prosols, showing them in a bootstrap template, and showing for each a button to validate or not.
The issue is that all buttons point to the first prosol. It seems that the prosol ID is not accurately passed to the controller.
No route matches {:action=>"unpro1", :article_id=>5, :controller=>"prosols", :id=>nil} missing required keys: [:id]
Here is the code.
article#show.html.erb - Adding lines from original Code
<% if admin_signed_in? %>
<% #article.prosols.in_groups_of(2) do |group| %>
<div class="container-fluid">
<% group.compact.each do |prosol| %>
<div class="col-md-6">
<div class="box3">
<h4><%= prosol.title %></h4> <br>
<%= prosol.body %> <br>
<% if prosol.profeat1 == false %>
<%= button_to "Do it", pro1_article_prosol_path(:article_id => #article.id, :id => #prosol.id), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", unpro1_article_prosol_path(:article_id => #article.id, :id => #prosol.id), :class => 'btn btn-info'%>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
<% end %>
prosols_controller.rb
def pro1
#article = Article.find(params[:article_id])
#prosol = #article.prosols.find(params[:id])
#prosol.update(profeat1: true)
redirect_to article_path(#article)
end
def unpro1
#article = Article.find(params[:article_id])
#prosol = #article.prosols.find(params[:id])
#prosol.update(profeat1: false)
redirect_to article_path(#article)
end
routes.rb
resources :articles do
resources :prosols do
post 'pro1', on: :member
post 'unpro1', on: :member
end
end
Right now I think the issue is with passing the nested resource (prosol) ID to controller.
If you see a better/different way of achieving the end result, I will warmly welcome your advice.
Again, my goal is to display all prosols for an article, with an admin button to validate or not.
I have thoroughly tried everything else on StackO so far but to no avail.
Awaiting the Savior... Thanks in advance.
EDIT : THIS IS THE SOLUTION - article#show.html.erb
<% if prosol.profeat1 == false %>
<%= button_to "Do it", pro1_article_prosol_path(:article_id => #article.id, :id => prosol.id), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", unpro1_article_prosol_path(:article_id => #article.id, :id => prosol.id), :class => 'btn btn-info'%>
<% end %>
My initial error had 2 sources:
- pointing to the nested prosol with an # instead of no pointer, as it was already pointed to in the loop
- and bad leftovers in the Articles controller, as follows:
def show
#article = Article.find(params[:id])
#prosols = #article.prosols.all <--- wrong
#prosol = #article.prosols.build <--- wrong
end
Great. Now it's beer o'clock.
Shouldn't this:
<% if prosol.profeat1 == false %>
<%= button_to "Do it", pro1_article_prosol_path(:article_id => #article.id, prosol.id => prosol.id), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", unpro1_article_prosol_path(:article_id => #article.id, prosol.id => prosol.id), :class => 'btn btn-info'%>
<% end %>
look like this?
<% if prosol.profeat1 == false %>
<%= button_to "Do it", pro1_article_prosol_path(:article_id => #article.id, :id => prosol.id), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", unpro1_article_prosol_path(:article_id => #article.id, :id => prosol.id), :class => 'btn btn-info'%>
<% end %>
Or even better:
<% if prosol.profeat1 == false %>
<%= button_to "Do it", pro1_article_prosol_path(#article, prosol), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", unpro1_article_prosol_path(#article, prosol), :class => 'btn btn-info'%>
<% end %>
The issue appears to be that you are using #prosol in your button, which has not been assigned and is therefore returning nil.
Your loop defined in your comment, sets prosol, which is not #prosol. Drop the '#' symbol and you should be fine.
-- edit--
As in id => prosol.id ...
<% if prosol.profeat1 == false %>
<%= button_to "Do it", ..., :id => prosol.id), :class => 'btn btn-info'%>
<% else %>
<%= button_to "Undo it", ..., :id => prosol.id), :class => 'btn btn-info'%>
<% end %>
Your error is showing id => nil because #prosil is a nil object.

rails ignores my redirect

Rails is ignoring my redirect.
Use Case:
user navigates to his account and selects the option to display his subscription status
app lists his current subscription and the option to cancel it
user cancels the subscription
app updates the subscription record and should redirect the user back to the subscriptions action
-> but rails ignores this last step... any ideas what I am doing wrong?
Routes
map.resources :users, ..., :member => { ..., :subscriptions => :get, :subscribe => :post, :unsubscribe => :put}
Controllers:
def subscriptions
#tradesman = User.find_by_id(params[:id])
#subscription = #tradesman.current_subscription || Subscription.new
#all_subscriptions = Subscription.find(:all)
end
def subscribe
#tradesman = User.find_by_id(params[:id])
#subscription = current_user.subscriptions.build(params[:subscription])
#subscription.update_attributes(:started_at => Time.zone.now)
#subscription.save
redirect_to :action => 'subscriptions', :id => #tradesman.id
end
def unsubscribe
#tradesman = User.find_by_id(params[:id])
#subscription = #tradesman.current_subscription
#subscription.update_attributes(:ended_at => Time.zone.now)
#subscription.save
redirect_to :action => 'subscriptions', :id => #tradesman.id
end
View:
<div class = 'wrapper'>
<%= render :partial => "my_account_leftbar" %>
<% form_for #subscription, :url => subscribe_user_path(current_user) do |f| %>
<% #all_subscriptions.each do |subscription| %>
<div class="field">Start: <%= subscription.started_at %></div><br><br>
<% end %>
<% if #subscription.new_record? %>
<div class="field">
<%= f.check_box :subscription_type %>
<div class="actions">
<%= f.submit "Subscribe", :class => "button mr8" %>
</div>
</div>
<% else -%>
<%= f.check_box :subscription_type, :value => #subscription.subscription_type, :disabled => true %>
<% form_for #subscription, :url => unsubscribe_user_path(current_user) do |f| %>
<div class="actions">
<%= f.submit "Unsubscribe", :class => "button mr8" %>
</div>
<% end %>
<% end %>
<% end %>
</div>
Use redirect_to instead of render (last method call in your unsubscribe action).
Found the bug in the view where I nested the 'unsubscribe' form within the 'subscribe' form - what didn't make sense.
I rearranged my view (separated those two forms, one in the 'if' part and the other in the 'else' part. Works fine now:
<div class = 'wrapper'>
<%= render :partial => "my_account_leftbar" %>
<% #all_subscriptions.each do |subscription| %>
<div class="field">Start: <%= subscription.started_at %></div><br><br>
<% end %>
<% if #subscription.new_record? %>
<% form_for #subscription, :url => subscribe_user_path(current_user) do |f| %>
<div class="field">
<%= f.check_box :subscription_type %>
<div class="actions">
<%= f.submit "Subscribe", :class => "button mr8" %>
</div>
</div>
<% end %>
<% else -%>
<% form_for #subscription, :url => unsubscribe_user_path(current_user) do |f| %>
<%= f.check_box :subscription_type, :value => #subscription.subscription_type, :disabled => true %>
<div class="actions">
<%= f.submit "Unsubscribe", :class => "button mr8" %>
</div>
<% end %>
<% end %>
</div>

Ajax and voting

I have a parent class Car and the /cars/show page lists all of the reviews associated with it. The reviews can be voted on. I am having some difficulty getting the :votes_count to update by JavaScript.
/votes/create.js.erb
$("#votes").html("<%= review.votes_count %>") // this does not work
/cars/show
<% #car.reviews.each do |review| %>
<p id='votes'><%= pluralize(review.votes_count, 'vote') %></p>
<% if current_user %>
<%= form_for(#vote, :remote => true) do |f| %>
<%= f.hidden_field "review_id", :value => review.id %>
<%= f.hidden_field "user_id", :value => current_user.id %>
<%= f.submit "vote" %>
<% end %>
<% end %>
<br />
<%= review.content %>
<% end %>
create.js.erb
<% #car.reviews.each do |review| %>
$("#review_<%= review.id %>").html("<%= pluralize(review.votes_count, 'vote') %>");
<% end %>

Resources