Update JSon parsed vote using Ruby on Rails, possible without JQuery? - ruby-on-rails

I am trying to make the vote total editable from a JSon parsed API. I have the following in my rosters controller:
def index
#rosters = HTTParty.get('https:api', :headers =>{'Content_Type' => 'application/json'})
#allrosters = Roster.all
#allrostershash = {}
#allrosters.each do |roster|
image_url = roster['image_url']
#allrostershash[ image_url ] = roster
end
#rosters.each do |roster|
img_url = roster['image_url']
unless #allrostershash[img_url]
Roster.create(roster)
end
end
end
def count_vote
roster_id = params[:id]
roster = Roster.find_by(roster_id)
newvote = roster.vote + 1
if roster.update({vote: newvote})
redirect_to rosters_path
end
end
Roster is the name of my class above. In my rails views I have the following:
<% #rosters.each do |roster| %>
<div class='each'>
<%= image_tag(roster['image_url'], class: 'image') %>
<%= hidden_field_tag(roster['id']) %>
<p class='name'> <%= roster['name'] %> </p>
<p class='title'> <%= roster['title'] %> </p>
<p> <%= roster['bio'] %> </p>
<p> <b> Want to work with <%= roster['name'] %>? </b> <%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path, method: :patch %>
<br>
<%= roster['vote'] %> People have said Yes! </p>
<br>
</div>
<% end %>
I would like that every time someone clicks on yes.jpg, the roster['vote'] increases by 1.
Currently my routes are set up as follows:
get 'rosters', to: 'rosters#index'
patch 'rosters', to: 'rosters#count_vote'
I'm trying to accomplish this without jquery or ajax, that's why I have the if roster.update portion to redirect to rosters_path, so it basically refreshes the page upon click. Right now it isn't updating the vote total however, I'm not sure what I'm missing. I would like to do it all on a single page so if its not possible without JQuery, any guidance in right direction is appreciated.

count_vote will silently fail if it cannot find your Roster or if the update cannot be saved. Change it so it raises an exception of anything fails.
def count_vote
roster = Roster.find(params[:id])
roster.vote += 1
roser.save!
redirect_to rosters_path
end
find will raise RecordNotFound if the Roster cannot be found. save! will raise an error if the changes cannot be saved.
These are the only params currently for some reason ActionController::Parameters {"_method"=>"patch", "authenticity_token"=>"qbORnCLNnI9P1zUZ02VEP3qJMwYOGa5sGw6KblPFj99mvjwZQj9VnDQ2e+6ZStJi3PJZ3MidSMsdoWlwOgBN9w==", "controller"=>"rosters", "action"=>"count_vote"} permitted: false> how would I add an id param? – Sohel 5 hours ago
I'm not very familiar with how views work, but I think as in this example, I believe you need to pass the roster into rosters_path.
<%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path(roster), method: :patch %>
Similarly, if you want count_vote to redirect back to the roster you just changed...
redirect_to rosters_path(roster)

Related

How to use Ruby on Rails Associations?

Description: I am following the toy_app tutorial on: https://www.railstutorial.org/book/toy_app
I am having issues with an Exercise question under section 2.3.3
Question: Edit the user show page to display the content of the user’s first micropost. (Use your technical sophistication (Box 1.1) to guess the syntax based on the other content in the file.) Confirm by visiting /users/1 that it worked.
Within my app/views/users/show.html.erb file. I tried using my #micropost.content object to display any content associated with the user.
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<p>
<strong>Email:</strong>
<%= #user.email %>
</p>
<p>
<strong>Content:</strong>
<%= (<%= #micropost.content %>) %>
</p>
<%= link_to 'Edit', edit_user_path(#user) %> |
<%= link_to 'Back', users_path %>
Result
NoMethodError in Users#show
undefined method 'content' for nil:NilClass
Conclusion
Do I need to generate a form_for for my posts for my app/view/user file? Or, because I'm setting my :content object within a private 'micropost_params' method in my microposts_controller.rb, that it will not allow object data transfer between controllers?
I tested within console the following lines of code to make sure association is working:
first_user = User.first
first_user.microposts
micropost = first_user.microposts.first
micropost.user
I feel that I need to define a method within my User controller file that gives access to my :content object within my MicroPosts Class.
Your show action should look something like the following.
def show
#user = User.find(params[:id])
#micropost = #user.microposts.first
end
Now, in the view, you can access the micropost's content using #micropost.content. What if the user has no microposts associated with him(hasn't written a micropost)? In that case, #user.microposts.first will be nil. If you're not sure what I mean, try playing with it in the rails console.
<% if #micropost %>
<%= #micropost.content %>
<% else %>
<p> User has no microposts </p>
<% end %>

Rails: Why isn't the 'create' action saving the newly created Quiz instance?

My form gets passed a 'new' Quiz (not saved to the database). My form partial looks like this:
<%= form_for(#quiz) do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%= f.check_box(:answer2) %>
<%= f.check_box(:answer3) %>
<%= f.check_box(:answer4) %>
<%= f.check_box(:answer5) %>
<%= f.check_box(:answer6) %>
<%= f.check_box(:answer7) %>
<%= f.check_box(:answer8) %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
Here is my QuizzesController#create action:
def create
#results = Quiz.create(post_params) #from private method
if #results.save
redirect_to results_path
else
#error handle here
end
end
...which gets triggered when the user clicks 'get my results' on my quiz form. And the post_params method looks like this:
def post_params
params.require(:quiz).permit(:id, :user_id, :answer1, :answer2, :answer3, :answer4, :answer5, :answer6, :answer7, :answer8) #add other attributes here
end
My results/index.html.erb looks like this:
<div class="container">
<!-- Example row of columns -->
<div class="row">
<h1>Results</h1>
<p><%= #results.inspect %></p>
</div>
</div>
But that 'inspected' Quiz instance returns 'nil' for all the answers1, answers2 etc attributes. Any idea why that would be? Is there something I'm NOT doing to save the user's answers to the database?
The reason it shows nil is because you are not setting the variable.
After creating and saving, you redirect to results_path and the variable #results does not persist during a redirect. Without seeing the full code, I'll have to guess at your naming conventions but there are two ways to do this.
1) If you want to redirect to the index then in the code for your index action, you can set the variable:
#results = Quiz.last
This is easy to work with in development because you are the only user and this will always return the last quiz you created. Not so great in production.
2) The alternative is to redirect to the show action for that quiz.
def create
#results = Quiz.new(post_params)
if #results.save
redirect_to result_path(#results)
else
# error handle here
end
end
Again, I have had to guess that result_path is the correct path. Without seeing the full routes file, I cannot be sure but you can rename accordingly if necessary.

Parameters not being read even though they appear to be passed

I'm making a form that creates more than one record for the user depending on how many items the user decides to check off in the form using checkboxes.
Currently, I'm running into an error where param is missing or the value is empty: itemrecord even though in the log, it appears that params are passing through:
{"utf8"=>"✓", "authenticity_token"=>"m2NMruoFRr6lpsuVMK9UthlY0bsJsPmf1LWce2uKaH4=", ":item_name"=>["Backpack", "Water filter"], "commit"=>"Go!"}
Model relationship is that a User has_many :inventories
Controller code:
def create
#itemrecord = #current_user.inventories.build
items_to_be_saved = []
inventory_params.each do |i|
items_to_be_saved << ({ :signup_id => #current_user.id, :item_name => i })
end
if Inventory.create items_to_be_saved
flash[:success] = "Thanks!"
redirect_to root_path
else
render new_inventory_path
end
end
def inventory_params
params.require(:itemrecord).permit(:item_name)
end
View code:
<%= form_for #itemrecord do |f| %>
<!-- In case you're wondering, the #wishlist below is basically a hash of categories of items and items. This hash is updated in the controller, and then used by multiple views to create the same table of items. -->
<% #wishlist.each do |category, list| %>
<div class="col-xs-2">
<div class="form-group box">
<h5> <%="#{category}"%> </h5>
<% list.each do |thing| %>
<%= check_box_tag ":item_name[]", "#{thing}" %>
</br>
<% end %>
</div>
</div>
<% end %>
<%= f.submit "Go!", class: "btn btn-primary btn-large btn-block" %>
</div>
<% end %>
By the way I also tried changing :item_name to :item_names to account for the array based on what else I read on SO, but that didn't fix it either
Take a look at your inventory_params function. You're saying that you require an itemrecord, and permit an item_name attribute. Observe:
def inventory_params
params.require(:itemrecord).permit(:item_name)
end
However, in the parameters being passed, there is no reference to an itemrecord object whatsoever, but there is a reference to item_name. A quick change to your inventory_params method, removing the :itemrecord requirement and instead requiring :item_name, will fix your issue.
def inventory_params
params.require(:item_name)
end
While this isn't necessarily the best way to go about doing this (I'd suggest reading up on your Active Record Form Helpers), it should solve your issue.

undefined method `comments' for nil:NilClass - listing for a specific user

There are posts, comments & users. I want to post number of comments for a specific user in comments list on Post show page. I know I need to define #user, but I don't know how to define it, so that it shows specific number for every user. User is author of the comment.
Post controller
def show
#post = Post.find(params[:id])
#comment = Comment.new
#comments = Post.find(params[:id]).comments.order(created_at: :desc)
#user = ???
end
Post /show action - error is for - #user.comments.count
<div class="row">
<% #comments.each do |comment| %><br>
<div class="col-sm-4"> <%= link_to comment.user.name, user_path(comment.user) %> <br>
<%= image_tag(comment.user.smallimage) %><%= #user.comments.count %>
</div>
<div class="col-sm-8"> <b><%= comment.title %>:</b>
<div>
<% if comment.content.length > 250 %>
<%= truncate(comment.content, length: 250) %>
<%= link_to_function '...Read more', "$(this).parent().html('#{escape_javascript comment.content}')" %>
<% else %>
<%= comment.content %>
<% end %>
</div>
</div>
<% end %>
</div>
If you define an #user you will only have one user or a group of users that doesn't relate to your comments. You don't need it. You can just use the relationship between user and comment like this:
<%= comment.user.comments.count %>
Note that this will run a database query for each comment to get the total comment count for that user. For performance reasons you may want to use a counter cache for this instead.
If you defined the association in the post model belongs_to :user then you can probably do #user = #comment.user
But, if that's the case then you can call that from the view with #comment.user.name or something like that.
I'd like to see the whole codebase if you've pushed to GitHub.

form_for save input values to session variables

I am trying to create a compare functionality for an index of schools. Currently I am using the following code which takes any checked school and adds it to the school_ids[] in the params.
In my gemfile:
gem 'will_paginate'
In my school's index.html.erb:
<%= form_tag compare_path, :method => 'get' do %>
<%= submit_tag "Compare" %>
<ul>
<% #schools.each do |school| %>
<li>
<%= check_box_tag'school_ids[]', school.id %>
<%= link_to school.name, school %><br>
<%= school.city %>, <%= school.state %>
</li>
<% end %>
</ul>
<% end %>
In my school controller I have:
def compare
#schools = School.find(params[:school_ids])
end
This works great as long as all of the check schools are on the same page. But since I'm using will_paginate to paginate the list of schools, if I change pages, the check boxes do not persist. I'm assuming I need to save to sessions somehow.
Do you mean you want to be able to add a check mark to a school A on page 1 of the index, go to page 2 of the index and add another check mark for school B, then submit the compare form and see schools A and B? If that's the case, then you're correct, you need to get the check boxes into the session. Attach a js click event, like
$('.checkbox_class').click(function(){
$.post('update_session_method', { school_id: $(this).val(), checked: $(this).is(:checked)]);
});
then add a controller method
def update_session_method
session[:school_ids] ||= []
if params[:checked]
session[:school_ids] << params[:school_id]
else
session[:school_ids].delete(params[:school_id])
end
end
then your compare method
def compare
#schools = School.find(params[:school_ids].merge(session[:school_ids] || []))
end

Resources