Missing params when using a partial - ruby-on-rails

let me start that I am new to rails, so far I have been able to solve all the issue I have had until now. I can confirm that my database is set and the relationships are working. Here is my issue, the app is similar to a project management tool. I have users that can create ski swaps and then search for vendors, then I render the results with javascript( ajax) so I dont have to reload the page. I added a badge so that I can use this to add the user as a vendor. As of right now I can get the user params no problem but the skiswap params I can't seem to get them to comeover I have tried. if I hardcode it it will work so I'm close but can not figure this out
Inside my
skiswap#index I have this for the search Above this I use #skiswap
<%= form_tag search_vendors_path, remote: true, method: :get do %>
<div class='form-group row'>
<div class ="input-group col-sm-3">
<%= text_field_tag :search, params[:search], placeholder: "Shop name, email, or contact...", autofocus: true, class: "form-control form-control-sm"%>
<div class="input-group-prepend">
<%= button_tag type: :submit, class: "btn btn-info btn-sm", id: "small-serach" do %>
<i class="fas fa-search" id = "search-icon"></i>
<% end %>
</div>
</div>
</div>
<% end %>
My search is working and this is what I have in the VendorController
def search
#users = User.where(["concat_ws(' ' , first_name, last_name, email, company ) ILIKE ?", "%#{params[:search]}%"])
respond_to do |format|
format.js{ render partial: 'skiswaps/result'}
end
end
My results are here and this is the badge I use to add new vendor, currently I have it hard coded because I cant figure it out. I am using j render for my results... I have tried skiswap_vendors_path(vendor: user, skiswap_id: #skiswap.id) also skiswap_vendors_path(vendor: user, skiswap: #skiswap) #skiswap is showing up as nil. Wasnt sure if it because my results are part of a partail, they dont seem to have the params that should be in show page.
<% #users.each do |user| %>
<tr>
<td><%= link_to "Add", skiswap_vendors_path(vendor: user, skiswap_id: 4),
class: "badge badge-success", method: :post %></td>
<td> <strong>Shop: </strong><%= user.company %> </td>
<td> <strong>Contact: </strong><%= user.first_name %> <%= user.last_name %>, <%= user.email%></td>
</tr>
<% end %>
Then in my VendorController I have this to create, which only works if I hardcode it
def create
vendor = User.find(params[:vendor])
skiswap = Skiswap.find(params[:skiswap_id])
skiswap.vendors.build(user_id: vendor.id)
if skiswap.save
flash[:notice] = "You add #{vendor.company} as a vendor"
else
flash[:notice] = "Sorry something went wrong, try again later"
end
end
This is what I have for routes
get 'search_vendors', to: 'vendors#search'
resources :skiswaps do
resources :vendors
end

I had to add in a hidden field tag to get the #skiswap.id through
<%= form_tag search_vendors_path, remote: true, method: :get do %>
....
<%= hidden_field_tag :skiswap_id, #skiswap.id %>
<% end %>

Related

using acts_as votabable gem for likes and want to change the heart color to red permanently after user has liked

I am using the acts_as votable gem and I manage to change the heart color to red after a user has clicked on the heart by using javascript. However, once the server refreshes the heart goes gray again and there is no indication whether a user has liked the current post or not. How can I change the color permanently after a user has liked. My idea is to set a boolean to true in the vote table and then check that somehow in the view. But I am not sure how to implement it exactly. Any help would be much appreciated.
lists_controller.rb
def vote
if !current_user.liked? #list
#list.liked_by current_user
elsif current_user.liked? #list
#list.unliked_by current_user
end
vote.js.erb
<% if current_user.liked? #list %>
$('.fa-heart').addClass('liked');
<% else %>
$('.fa-heart').removeClass('liked');
<% end %>
$('.likes-count').html("<%= #list.get_upvotes.size %>")
show.html.erb
<div class="like">
<%= link_to like_list_path(#list), :class => "like-btn", method: :put, remote: :true do %>
<i class="fa fa-heart"></i>
<% end %>
<%= link_to "", "data-toggle" => "modal", "data-target" => "#likeModalLong" do %>
<span class="likes-count"><%= #list.get_upvotes.size %></span>
<% end %>
</div>
You can create a helper to make the liked css class persistent in you view:
application_helper
def liked_list(list)
liked = current_user.liked?(list) ? 'liked' : ''
content_tag(:i, '', class: "fa fa-heart #{liked}")
end
show.html.erb
<%= link_to like_list_path(#list), :class => "like-btn", method: :put, remote: :true do %>
<%= liked_list(#list) %>
<% end %>

Render in a different order on the page breaks the routing

I have Challenges containing Puns, and it is possible to vote on puns. On the Challenge Show page, all puns are rendered and show their votes count. This is currently on the view page:
<%= render #challenge.puns.reverse %>
<br>
<div id="form">
<%= render "puns/form" %>
</div>
I want the puns form to appear above the items (puns) already submitted. But if swap them around, like this:
<div id="form">
<%= render "puns/form" %>
</div>
<%= render #challenge.puns.reverse %>
I get a controller error and pun.id is not suddenly not available and the voting link breaks.
No route matches {:action=>"upvote", :challenge_id=>"9", :controller=>"puns", :id=>nil}, missing required keys: [:id]
Here is the puns/form part that is causing the issue
<% if signed_in? %>
<% if current_user.voted_for? pun %>
<%= pun.votes_for.size %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% else %>
<%= link_to like_challenge_pun_path(#challenge, pun.id), method: :put do %>
<span class="heart_like">❤</span> <%= pun.votes_for.size %>
<% end %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% end %>
<% end %>
It is the like_challenge_pun_path that throws an error but I cannot understand why. I am declaring #challenge again here, so it should be able to get the id.
Here is the form for the puns:
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
<span class=".emoji-picker-container">
<%= f.text_area :pun_text, placeholder: "Add pun", data: { emojiable: true } %>
</span>
<%= f.submit %>
<% end %>
Also, here is my routes setup
resources :challenges do
resources :puns do
member do
put "like", to: "puns#upvote"
put "dislike", to: "puns#downvote"
end
end
end
and the corresponding action to upvote
def upvote
#pun = #challenge.puns.find(params[:id])
#pun.upvote_by current_user
redirect_to #challenge
end
Can anyone help?
I think the code is for the puns collection.
I assume the issue is that in the form you have something like:
#challenge.puns.build
So in #challenge.puns collection appears not persisted record (without id), so path for this model cannot be generated.
As a quick solution I suggest:
<%= render #challenge.puns.reverse.select(&:persisted?) %>
UPDATE:
As I assumed you have
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
You can also try:
<%= form_for([#challenge, Pun.new]) do |f| %>
Or solve it in the controller. But need to see controller code for it.

Devise deletes credentials

i implemented a friendship model using rails 3.. now i want to enable the users to add new friends...from the looks of it, i guess i need 2 for loops...one for looping all the users and another one for checking if that user is already a friend.... but if i use 2 for loops, i don't get the result that i am expecting and the email of the users who are alraedy the friends of current user prints and the address gets printed multiple times (because of the 2nd for loop as i am printing it inside the loop) .. is there any other way to get around this issue????
code:
this is my view file:
<center>Bragger's list<center><br/>
<p>
<% for user in User.all %>
<% if current_user.email!= user.email %>
<% for friend in current_user.friends %>
<% if friend.email!=user.email %>
<p>
<%= user.email %> <%= link_to 'Add as Friend' , friendships_path(:friend_id => user), :method => :post %>
</p>
<br/>
<%end%>
<%end%>
<%end%>
<%end%>
The best approach to this is to filter the list of users in your controller that is not yet a friend of the current_user. You can do that by
#potential_friends = User.where('id != ? AND id NOT IN (?)', current_user.id, current_user.friend_ids)
Then just loop over this variable in the view
<center>Bragger's list<center><br/>
<p>
<% #potential_friends.each do |user| %>
<p>
<%= user.email %> <%= link_to 'Add as Friend' , friendships_path(:friend_id => user), :method => :post %>
</p>
<br/>
<% end %>
</p>
How about doing something else,
User.where('user_id not in (?)', current_user.friends.map(&:id).push(current_user.id))
This would get all the users from the database that are not your current_user's friends and then you have only to loop once.

Rails 3 multi-part search

I've spent a few days on this and just haven't been able to get my head around how to apply a scope or other method to this. I've also tried some search gems but because I'm at such a basic level, wanted to keep things as simple as possible. The effort below is loosely based on rails casts #37 "simple search" tutorial. Its the only one that's been marginally successful.
My problem; I want to run a search on year, make, model, engine(if any), drilling down to the desired vehicle(s). To make things easy on me, I did one search per page. Currently I'm not able to carry the previous search params over to the current search. I'm sure there are better ways of doing this than the one below, and I'm open to suggestions. I just haven't been able to successfully adapt examples I've found online.
The Database:
I have a postgres database table named "carinfo", that table has columns "id, caryear, carmake, carmodel, carengine, submodel, website1, website2, website3". I've populated it with some test data with a dozen or so vehicles.
controllers/listing_controller.rb
To simplify things I haven't used a model yet so its all in the controller:
class ListingController < ApplicationController
include ListingHelper
def year
#searchyr = Carinfo.find(:all)
end
def make
#searchmk = Carinfo.find(:all, :conditions => ['caryear LIKE ?', "%#{params[:year]}%"])
end
def model
#searchmdl = Carinfo.find(:all, :conditions => ['caryear LIKE ? AND carmake LIKE ?', "%#{params[:year]}%", "%#{params[:make]}%"] )
# '%2009%' static values work ok
end
def engine
#searcheng = Carinfo.find(:all, :conditions => ['caryear LIKE ? AND carmake LIKE ? AND carmodel LIKE ?', "%#{params[:year]}%", "%#{params[:make]}%", "%#{params[:model]}%"])
end
def selectedcar
#searchres = Carinfo.find(:all, :conditions => ['caryear LIKE ? AND carmake LIKE ? AND carmodel LIKE ? AND carengine LIKE ?', "%#{params[:year]}%", "%#{params[:make]}%", "%#{params[:model]}%","%#{params[:engine]}%"])
end
end
views/listing/year.html.erb
<% provide(:title, "Year") %>
<h1>Year Search - Under: Listing</h1>
<%= form_tag(make_path, :method => "get") do %>
<%= select_tag :year, options_for_select(#searchyr.collect{|y| [y.caryear, y.caryear]}.uniq), {:onchange => 'this.form.submit()'} %>
<% end %>
<!-- this can be deleted once everything is working it just helps see what's filtered -->
<ul>
<% for search in #searchyr %>
<li>
<%= search.caryear %>
<%= search.carmake %>
<%= search.carmodel %>
</li>
<% end %>
</ul>
<center><%= button_to "Reset Search", year_path, class: "btn btn-large btn-primary" %></center>
views/listing/make.html.erb
<% provide(:title, "Make Search") %>
<h1>Make Search - Under: Listing</h1>
<%= form_tag(model_path, :method => "get") do %>
<%= select_tag :make, options_for_select(#searchmk.collect{|y| [y.carmake, y.carmake]}.uniq), {:onchange => 'this.form.submit()'} %>
<% end %>
<center><%= button_to "Reset Search", year_path, class: "btn btn-large btn-primary" %></center>
views/listing/model.html.erb
<% provide(:title, "Model Search") %>
<h1>Model Search - Under: Listing</h1>
<%= form_tag(engine_path, :method => "get") do %>
<%= select_tag :model, options_for_select(#searchmdl.collect{|y| [y.carmodel, y.carmodel]}.uniq), {:onchange => 'this.form.submit()'} %>
<% end %>
<center><%= button_to "Reset Search", year_path, class: "btn btn-large btn-primary" %></center>
views/listing/model.html.erb
<% provide(:title, "Engine Search") %>
<h1>Engine Search - Under: Listing</h1>
<%= form_tag(selectedcar_path, :method => "get") do %>
<%= select_tag :engine, options_for_select(#searcheng.collect{|y| [y.carengine, y.carengine]}.uniq), {:onchange => 'this.form.submit()'} %>
<% end %>
<center><%= button_to "Reset Search", year_path, class: "btn btn-large btn-primary" %></center>
views/listing/selectedcar.html.erb
<% provide(:title, "Selected Car") %>
<h1>Selected Car - Under: Listing</h1>
<center><%= button_to "Reset Search", year_path, class: "btn btn-large btn-primary" %></center>
<ul>
<% for search in #searchres %>
<li>
<%= search.caryear %>
<%= search.carmake %>
<%= link_to search.carmodel, search_path(search) %>
</li>
<% end %>
</ul>
config/routes.rb
Just the section dealing with this problem:
match '/year', to: 'listing#year'
match '/make', to: 'listing#make'
match '/model', to: 'listing#model'
match '/engine', to: 'listing#engine'
match '/selectedcar', to: 'listing#selectedcar'
As always, help is greatly appreciated.
Thanks
Mike
First off, you're controller doesn't need all of those methods, do something like this:
class ListingController < ApplicationController
include ListingHelper
def search
#search = Carinfo.where('caryear LIKE ?', params[:year]) unless params[:year].blank?
#search = #search.where('carmake LIKE ?', params[:make]) unless params[:make].blank?
etc etc...
end
end
Then just have one form that has all of the inputs that you'd like to search

How do I implement a show all comments feature in ruby on rails?

I'm implementing show/hide feature for users comments.
Discussed here: https://stackoverflow.com/a/10174194/439688
My aim was to:
1. Limit the default shown comments to 2.
2. Have a span with text that states the number of total comments for that particular micropost and when clicked by a user have it expand and show all comments for that micropost. I would be using Jquery/Ajax to hide, show, prepend etc.
The first change was to limit the amount of comments shown to the user and I achieved this by creating a method in my helper called "comments" and here I pass in the id of the micropost the comment belongs to.
def get_comments(micropost_id)
Comment.limit(2).order("created_at DESC").where(:micropost_id => micropost_id)
end
Now the each loop that loops through each comment will only show the 2 most recent comments.
<<% #microposts.each do |m| %>
<% if m.poster_id.nil? %>
<div class="postHolder">
<nav class="micropostOptions">
<ul class="postMenu">
<li class="deletePost"><%= link_to content_tag(:span, "Delete post"), m, :method => :delete, :confirm => "Are you sure?", :title => m.content, :class => "message_delete", :remote => true %>
</li>
<li class="disableCommenting"><%= link_to content_tag(:span, "Pause commenting"), "2" %></li>
<li class="blockCommenter"><%= link_to content_tag(:span, "Block commenter"), "3" %></li>
<li class="openInNewWindow"><%= link_to content_tag(:span, "Open in new window"), "4" %></li>
<li class="reportAbuse"><%= link_to content_tag(:span, "Report abuse"), "5" %></li>
</ul>
</nav>
<%= link_to image_tag(default_photo_for_current_user, :class => "poster_photo"), current_users_username %>
<div class="post_content">
<div class="post_container">
<div class="mainUserNameFontStyle"><%= link_to current_users_username.capitalize, current_users_username %> - <div class="post_time"> <%= time_ago_in_words(m.created_at) %> ago.</div>
</div>
<%= simple_format h(m.content) %> </div>
<div class="commentsCount">
<%= content_tag :span, pluralize(m.comments.count, 'comment'), :class => "view_all_comments" if m.comments.any? %>
</div>
<% if m.comments.any? %>
<% comments(m.id).each do |comment| %>
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(comment), :class => "commenter_photo"), commenter(comment.user_id).username %>
<div class="commenter_content"> <div class="userNameFontStyle"><%= link_to commenter(comment.user_id).username.capitalize, commenter(comment.user_id).username %> - <%= simple_format h(comment.content) %> </div>
</div><div class="comment_post_time"> <%= time_ago_in_words(comment.created_at) %> ago. </div>
</div>
<% end %>
<% end %>
<% if logged_in? %>
<%= form_for #comment, :remote => true do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :micropost_id, :value => m.id %>
<%= f.text_area :content, :placeholder => 'Post a comment...', :class => "comment_box", :rows => 0, :columns => 0 %>
<div class="commentButtons">
<%= f.submit 'Post it', :class => "commentButton", :disable_with => "Post it" %>
<div class="cancelButton"> Cancel </div>
</div>
<% end %>
<% end %>
</div>
</div>
From here this is where it gets confusing for me. I got slightly further using link_to but then decided I'd prefer not to have the url to the comments count show in the browser status bar. This is why I switched to using span.. but now it's not quite easy to do what I wish to do as I can't use the link_to/remote => true now.
How do I make it so when a user clicks the comment count span an ajax call is made pointing to:
def load_comments
#load_comments = Comment.where(:micropost_id => params[:id])
respond_to do |format|
format.js { render :load_comments }
end
end
I thought about putting a click function in users.js but how would I pass the params of the micropost that is in the each loop in the code above into users.js? I don't think it's possible.
All my comment posting is done via ajax but because I used forms for these it was so much easier for me to just add remote => true and create some js templates and do something on success of ajax post.
Not sure if I'm even going about this the right way. I'd appreciate some help/advice from more experienced rails programmers.
Kind regards
Rails partial
#Display all the comments based on local passed to this partial
# Initially pass limit as 2(or whatever you want). then on click of span pass limit as nil. then you can check if limit is nil you can query the model without limit specifier.
<% #comments = Comment.custom_find(#your_params) %>
<% #comments.each do |comment| %>
<%= comment.title %>
<% end %>
javascript/jquery
function load_all_comments(id)
{
new Ajax.Updater('show_comments',
'<%=url_for(:controller => "your_controller", :action => "your_action")%>', {
parameters: {'id':id },
method: 'get',
onSuccess: function(request){
div_comments = document.getElementById("partial_comments_list");
div_comments.innerHTML = request.responseText;
}
});
} // you can call this js function on span click. use jquery if you want.
Controller:
Then inside your_action of your_controller, dont forget to render the partial
render :partial => "show_comments", :layout => false
Edit:
you can even pass locals to your partial
render :partial => "show_comments", :locals => {:post => #post}
Using this every time your partial view will get updated, on the basis of locals you pass.
of course this is just an example not a complete code/solution.
There may be better ways. but this worked fine for me.
Another option is to just output all of the comments and hide the ones you don't want to show first. <div class="hidden_comments" style="display:none;"> a comment </div>
Then just have some javascript to show them when the span is clicked?
<script type="text/javascript">
$("#span_id").click(function() {
$('.hidden_comments').show();
});
</script>
This works great if you do not don't have a ton of comments.
If you really want to do it your way, I have done it before but it gets messy.
Put this in your application.js
$('.comment_span').live('click', function () {
$.get(this.data_url, null, update_row, 'json');
return false;
});
Your span would look like this:
<span class="comment_span" data_url="http://website.com/resource/more_comments">
show all comments
</span>
This example returns the data as json, so I used the update_row function to update replace the comments data.
function update_row(data, status) {
$("#comments-table").append(data.html);
};
Here is what my controller looked like:
def more_comments
#comments = Comments.all
if #comments
respond_to do |format|
format.js {
render :json => {
:html => render_to_string(:partial => "comments"),
}.to_json
}
end
end
end
You should do this via your index action.
Pass a param to it to determine if you want to show all comments or just the current set (I'd use will_paginate to handle this.
Haven't looked too deep into your code as I'm on my phone right now, but something like this:
class CommentsController < ApplicationController
def index
If params[:show_all] == "true"
#comments = Comment.all
else
#comments = Comment.where(foo: bar).paginate(per_page: 2, page: params[:page])
end
end
Then you have it respond to JavaScript and send the page param with your Ajax request

Resources