Limit User to 1 Like/Dislike per Post - ruby-on-rails

I have a listing model (which allows comments) and users can like (thumbs up) or dislike (thumbs down) the listing. It works at the moment but I want to iterate over the likes for a specific listing, and if any like's user_id listing.likes.user_id matches the current users ID current_user.id then remove the form to like (users can add a reason why they are liking the listing)
<%= form_for([#listing, #listing.likes.build]) do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
I have something halfway there that checks if the current likes user_id matches the current user id, if so provide a link to delete (remove/unlike) the like.
<% if current_user.id == like.user_id %>
<%= link_to '[ Delete Like ]', [like.listing, like],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
How would I go about using the code to remove the like form if the user has already created a like/if the user's ID matches the user_id of a like created for a specific listing(something like this?)
<% if current_user.id == listing.likes.any.user_id %>
<% else %>
<%= form_for([#listing, #listing.likes.build]) do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
<% end %>

I think you had the right idea with the any method, but were not using it correctly. any can accept a block in which you can do your user_id comparison, like so:
<% if listing.likes.any{|like| like.user_id == current_user.id } %>
In this case, any will return true the instant the condition in the block evaluates to true.
Let me know whether this works.
Side Note
If my method works for you, you may like to further clean up your view code by moving that check in to the Listing model as a helper method. Something like this:
class Listing < ActiveRecord::Base
# ... other stuff
def has_comment_from?(target_user)
likes.any{|like| like.user_id == target_user.id }
end
end
And then you can simply call it from the view like so:
<% if listing.has_comment_from? current_user %>

Found a partial solution but it stops the user from commenting after 1 comment, not 1 comment per listing.
<% #listing.likes.each do |like| %>
<% if current_user.id == like.user_id %>
<% else %>
<%= form_for([#listing, #listing.likes.build]) do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
<% end %>
<% end %>

Related

Remove array from showing under my rails erb-form

I have a checkbox form where you can select many customers to attend a single event. The form works but there is an array of all customers under it and I can't figure out how to remove it.
events.rb
def addcustomer
#event = Event.find(params[:id])
#customer = Customer.all
end
routes.rb
resources :events do
get 'addcustomer', on: :member, as: 'add'
end
addcustomerform.html.erb
<%= form_for(#event) do |f| %>
<%= hidden_field_tag "event[customer_ids][]", nil%>
<%= #customer.each do |customer| %>
<%= check_box_tag "event[customer_ids][]", customer.id,
#event.customer_ids.include?(customer.id), id:dom_id(customer) %>
<%= label_tag dom_id(customer), customer.id %>
<%= label_tag dom_id(customer), customer.name %> --
<%= label_tag dom_id(customer), customer.email %> --
<%= label_tag dom_id(customer), customer.phone %>
<br>
<% end %>
<br>
<%= f.submit%>
<% end %>
Here is a photo of what the issue looks like:
Here is the repo
https://github.com/robbiesoho/fanfactory
I hope someone can help. Thank you
it is not the params that are shown there but all the customers.
If you replace <%= #customer.each do |customer| %> with <% #customer.each do |customer| %>
The difference is that I remove the =. The = means that the line should be added to the HTML as text. on that line is the #customer array, and the result f #customer.to_s is what you see there.
For more information, please read: What is the difference between <%, <%=, <%# and -%> in ERB in Rails?

Pass new parent object id to link_to

I am trying to save parent as well as child object at the same time using accepts_nested_attributes_for
Code in controller's new method:
def new
#project = Project.new
#project.instances.build
end
and form looks like this:
<%= simple_form_for(#project) do |f| %>
<%= f.input :name %>
<%= link_to "Add New Instance", new_project_instance_path(#project), id: "new_link", remote: true %>
<% end %>
The route entry for this is:
resources :projects do
resources :instances
end
And the fields that need to be displayed instances/_form.html.erb:
<%= form.simple_fields_for :instances do |i| %>
<%= i.input :user_id %>
<%= i.input :password %>
<%= i.input :service_url %>
<% end %>
The issue here project_id being :nil, it is giving error:
No route matches {:action=>"new", :controller=>"instances", :project_id=>nil} missing required keys: [:project_id]
I need to somehow call <%= render 'cdd_instances/form', form: f %>, so that the fields get rendered below the Project details, how should I implement this?
I think your #project is null you have to pass like:
new_project_instance_path(project_id: (#project || ''))
In this case you are not able to pass non-persisted #project to create this link_to url.
I believe you are looking for something like: cocoon.
<%= simple_form_for #project do |f| %>
<%= f.input :name %>
<h3>Instances</h3>
<div id="instances">
<%= f.simple_fields_for :instances do |instance| %>
<%= render 'instance_fields', f: instance %>
<% end %>
<div class="links">
<%= link_to_add_association 'add instance', f, :instances %>
</div>
</div>
<%= f.submit %>
<% end %>
Cheers!

rails: how to update multiple records using "accepts_nested_attributes"

Let's say I have a cat model and a life model. And let's say a cat (#cat) has_many lives, and a cat accepts_nested_attributes for a life.
Now, if I wanted to update 7 lives (#lives) at once, using one form_for(#cat), how would that form look like? This is what I've tried, but in this form only the attributes for the last life are passed to the params hash:
<%= form_for(#cat) do |f| %>
<% #lives.each do |life| %>
<%= f.fields_for(life) do |l| %>
<%= l.input :date_of_birth, as: :date %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You need to build the attributes in your controller
#cat = Cat.find(<criteria>)
#cat.lives.build
In your example, you have a loop inside a loop. Try this:
<%= form_for(#cat) do |f| %>
<%= f.fields_for(:lives) do |l| %>
<%= l.input :date_of_birth, as: :date %>
<% end %>
<%= f.submit %>
<% end %>

Rails 4 - Nested Attributes form only POSTing one field

I'm new to Ruby on Rails, and I'm looking create a system where users join a house, and then can leave notes to other users in their house. Each note should have individual permissions per other users in their house. When a user creates a note, they will be greeted with a form with a text area for the Note content, and then a list of all the other users in the house, with a dropdown indicating that users level of permission on that note.
I'm attempting to use Partials to make things nicer, as Permissions are a polymorphic class and will be used in other parts of our website. Right now, when a Note is submitted as a new note, only one Permission is being POSTed, instead of a Permission for each user, e.g.
Started POST "/notes" for 127.0.0.1 at 2015-11-03 11:37:47 -0500
Processing by NotesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8+fSG6oBsp4C3ikKc6mSNQYIB+mM5w3+42Y5tRVi5LOZY4a1lo0EApLo0WtSVNZ6/MO0yRwGitZzgZWaYR23mg==", "note"=>{"content"=>"okay...", "permissions_attributes"=>{"0"=>{"user_id"=>"0", "level"=>"3"}}}, "commit"=>"Post"}
I've spent a while comparing my View code with partials to others, and can't figure out why it's not submitting a permission for each user. Any advice? I can confirm that the permission that is submitted is created in the NoteController and created in the database correctly. It's just that instead of creating a permission for each user in the list, it's only creating the default permission.
Note Creation GUI
_form.html.erb
<%= form_for(#note) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new Note..." %>
</div>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission_new', :f => perm %>
<% end %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
_permission_new.html.erb
<% House.find(current_user.relationship.house_id).users.each do |user| %>
<%= render 'permission', :f => f, user: user %>
<% end %>
<% User.new(id: 0) do |user| %>
<%= render 'permission', :f => f, user: user %>
<% end %>
_permission.html.erb
<% if current_user.id != user.id %>
<div class="permission">
<% if user.id == 0 %>
Default Permission
<% else %>
<%= user.name %>
<% end %>
<%= f.hidden_field :user_id, value: user.id %><br />
<%= f.select :level, [["Read Only", 3], ["Read, Edit, and Delete", 1],
["Read and Edit", 2], ["Can't Read", 4]] %>
</div>
<% end %>
note_controller.rb
...
def new
#note = Note.new
#note.permissions.build
end
def create
#note = current_user.notes.build(note_params)
if #note.save
#perm_user = #note.permissions.create(user_id: current_user.id, level: 0)
flash[:success] = "Note Created"
redirect_to notes_path
else
render 'new'
end
end
...
private
def note_params
params.require(:note).permit(:content, permissions_attributes: [:user_id, :level])
end
In case anyone happens to be having the same problem, I figured it out.
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission_new', :f => perm %>
<% end %>
f.fields_for only technically creates one field per call. This means that in my _permission_new.html.erb file, where I have a loop creating a dropdown for each user in the house, and a dropdown for the default, all of those dropdowns were linked to the same field, and overwriting each other. Which is why only the last permission was being POSTed when a new Note was submitted. To fix this, you must call the f.fields_for multiple times in your form. In my case, I moved my f.fields_for into my _permission_new partial, and ended up with code like this.
_form.html.erb
...
<%= render 'permission_new', f: f %>
...
_permission_new.html.erb
<% House.find(current_user.relationship.house_id).users.each do |user| %>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission', :f => perm, user: user %>
<% end %>
<% end %>
<% User.new(id: 0) do |user| %>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission', :f => perm, user: user %>
<% end %>
<% end %>

Rails checkboxes and serialized data

I'm trying to figure out whats the best way to get checkboxes to properly show their current state. This is what I have in my form
<%= form_for #user, :url => user_notification_preferences_path(#user), :method => :put do |f| %>
<%= f.fields_for :notification_preferences, #user.notification_preferences do |p| %>
<%= p.check_box :notify_on_friend_post %>
<%= p.check_box :notify_on_friend_post %>
<%= p.check_box :notify_on_friend_request %>
<%= p.check_box :notify_on_friend_comment %>
<% end %>
<%= f.submit %>
<% end %>
notification_preferences is a serialized hash on my user model
class User < ActiveRecord::Base
serialize :notification_preferences, Hash
My issue that is no matter what I try, I can not get the check boxes to reflect the existing state of the hash values. IE, if the hash already contains :notify_on_friend_post => 1, then the check box for that value should be checked.
The form posts the data fine, and I'm able to update my model as well.
Update
using check_box_tag I can get this to work
<%= p.hidden_field :notify_on_friend_post, :value => "0" %>
<%= check_box_tag "user[notification_preferences][notify_on_friend_post]", "1", #user.notification_preferences[:notify_on_friend_post] == "1" ? true : false %>
ugly but working, still hoping I'm missing something very obvious
I ran into this problem and solved it in a simpler way.
<%= form_for #user do |f| %>
<%= f.fields_for :notifications, #user.notifications do |n| %>
<%= n.check_box :new_task, checked: #user.notifications[:new_task] == "1" %>
<% end %>
<%= f.submit %>
<% end %>
In this way you let the magic of check_box to the work and don't need to have a hidden_field because Rails will provide one for you. Still unsure why you need a "checked" field, but it seemed to not work without one.
Try something like this:
<%= form_for #user, :url => user_notification_preferences_path(#user), :method => :put do |f| %>
<%= check_box_tag "user[notification_preferences][]", :notify_on_friend_post, #user.notification_preferences.try(notify_on_friend_post) %>
<%= f.submit %>
<% end %>

Resources