a Facebook "like" or Twitter "follow" system - in Rails 3 - ruby-on-rails-3

Can anyone point me in the right direction to learn about how I could implement a system similar to facebook's "like" or Twitter's "Follow/Unfollow" system that I could create in Rails?
From what I understand I would need to use Unobtrusive Javascript.
I have a Thing model(has_many :likes) and a Like model (belongs_to :thing)
Any pointers?

You can do ajax call to a function and implement whatever functionality you like inside that function , (in this case "follow" ), you can do it with :
[link_to_function][1]
Incase , you are using rails 3.2.4 and it deprecated, you can use(This is from jeremy's comment.
https://gist.github.com/rails/rails/pull/5922#issuecomment-5770442 ):
module LinkToFunctionHelper
def link_to_function(name, *args, &block)
html_options = args.extract_options!.symbolize_keys
function = block_given? ? update_page(&block) : args[0] || ''
onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
href = html_options[:href] || '#'
content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
end
end

Related

Passing Rails ID to Angular

I have a Rails 3.2 app, where Angular code is calling a Rails route. I need to pass the route the (Rails) id of the page, and am having some difficulty. I have embedded the id onto the page using a hidden div, but cannot access it from Angular, in order to pass back into Rails.
I've reviewed this blogpost: http://spin.atomicobject.com/2013/11/22/pass-rails-data-angularjs/
Here is a similar question:
Rails route params in angular
I seem to be getting something but it is an object, not the id I need. A button is pressed which triggers the Angular call. An example url on the page would be, in which case I am trying to pass 833:
http://0.0.0.0:3000/batches/833/edit
worksheet.js.coffee
#WorksheetCtrl = ($scope) ->
.
.
$scope.exportCSV = ->
batchId = angular.element(document.querySelector("#data-batch-id"))
location.href = "/wizards/#{batchId}/worksheet_export.csv?#{Object.toQueryString($scope.getPostParams())}"
config/routes.rb
match 'wizards/:id/worksheet_export', :to => 'wizards#worksheet_export', :as => 'worksheet_export'
app/views/batches/edit.html.erb
<div ng-controller="WorksheetCtrl" ng-init="init()">
<div id="div-passed-data" data-batch-id="<%= #batch.id %>"></div>
app/controllers/wizards_controller.rb
def worksheet_export
Rails.logger.debug "id: #{params[:id]}"
Rails.logger.debug "params: #{params}"
.
.
Rails Console
Started GET "/wizards/[object%20Object]/worksheet_export.csv" for 127.0.0.1 at 2014-01-12 21:52:31 +0100
Processing by WizardsController#worksheet_export as CSV
Parameters: {"id"=>"[object Object]"}
id: [object Object]
params: {"controller"=>"wizards", "action"=>"worksheet_export", "id"=>"[object Object]", "format"=>"csv"}
SOLVED -- better solutions welcome
It seems rather convoluted, but I managed to pass in the id via the init() method and from there added it to the $scope.
app/views/batches/edit.html.erb
<div ng-controller="WorksheetCtrl" ng-init="init(<%= #batch.id %>)">
worksheet.js.coffee
$scope.init = (batch_id)->
console.log("batch: #{batch_id}")
$(document).ready ->
$('#editCriteriasModal').on 'hidden', ->
$scope.$apply ->
$scope.criteriaListValidation $scope.modalCriteriaList
$scope.search()
$scope.batchId = batch_id
.
.
$scope.exportCSV = ->
location.href = "/wizards/#{$scope.batchId}/worksheet_export.csv?#{Object.toQueryString($scope.getPostParams())}"

Using SQL with elastic search and tire

With my current setup I need to add some custom SQL statement that scopes some data with the Tire Gem.
I'm using Rails 3.2 with Ruby 1.9.3
In my Listing controller, I have the following:
#listings = Listing.search()
For my Listing.rb, I'm using the search methods with a number of filters such as:
def self.search(params={})
tire.search(load: true, page: params[:page], per_page: 50) do |search|
search.query { string params[:query], :default_operator => "AND" } if params[:query].present?
search.filter :range, posted_at: {lte: DateTime.now}
search.filter :term, "property.rooms_available" => params[:property_rooms_available] if params[:property_rooms_available].present?
search.filter :term, "property.user_state" => params[:property_user_state] if params[:property_user_state].present?
...
end
What I need to do is add this SQL statement into the search method so that it scopes by the lonitude and latitute. The 'coords' are passed in by parameters in the URL in the form
http://localhost:3000/listings?coords=51.0000,-01.0000 52.0000,-02.0000
(there is a white space between the -01.0000 and 52.0000.)
Currently I have:
sql = "SELECT title, properties.id, properties.lng,properties.lat from listings WHERE ST_Within(ST_GeometryFromText('POINT(' || lat || ' ' || lng || ')'),ST_GeometryFromText('POLYGON((#{coords}))'));"
I thought about trying to scope it within the controller by something like this?
def self.polyed(coords)
joins(:property).
where("ST_Within(ST_GeometryFromText('POINT(' || properties.lat || ' ' || properties.lng || ')'),ST_GeometryFromText('POLYGON((#{coords}))'))").
select("title, properties.id, properties.lng,properties.lat")
end
And this...
listings_controller.rb
def index
#listings = Listing.polyed(poly_coordinates).search()
end
It needs to return the results as #listings by HTML and the json format
http://localhost:3000/listings.json?
I'm already using RABL to automatically produce the json.
Is this possible?
Many thanks in advance.
Ryan
One possibility is to pass the options joins, where, etc. in the :load option.
But if you want to filter the returned results in the Rails code, a much better approach seem to be loading just record IDs with Tire (use the fields option to limit the fields returned), and then use them in your SQL query.

Rails 3 - routing and parameterized name

I use this rule in my model:
def to_param
"#{self.name.parameterize}"
end
and in my helper:
def articles_menu
menu = '<ul>'
Article.all.each do |article|
menu += '<li>'
menu += link_to "#{article.name}", article
menu += '</li>'
end
menu += '</ul>'
return menu.html_safe
end
but when I'll go to the /articles/my-new-flat, I'll get the error
ActiveRecord::RecordNotFound in ArticlesController#show
Couldn't find Article with id=my-new-flat
Missing I something else yet or is any problem in my app? I though for parameterizing of the name is needed only set up in the model the rule...
Use FriendlyId gem it has all what you need, here is the link https://github.com/norman/friendly_id/blob/master/README.md
Problem with your code is that rails under the hub is trying to query your model by "id" attribute, it is not querying "name" attribute. FriendlyId gem patches this for models you want

Rails current_page? "fails" when method is POST

I have a really simple problem. I have a page of reports and each report has its own tab. I'm using current_page? to determine which tab should be highlighted. When I submit any report, current_page? doesn't seem to work anymore, apparently because the request method is POST.
Is this the intended behavior of current_page? I have a hard time imagining why that would be the case. If it is, how do people normally get around this problem?
Here's an example of a current_page? call:
<li><%= link_to "Client Retention", reports_client_retention_path, :class => current_page?(reports_client_retention_path) ? "current" : "" %></li>
All right, it looks like I figured out the answer to my own question about 5 minutes after putting up a bounty. It looks like current_page? will always return false on POST.
Here's the source code for current_page?:
# File actionpack/lib/action_view/helpers/url_helper.rb, line 588
def current_page?(options)
unless request
raise "You cannot use helpers that need to determine the current " "page unless your view context provides a Request object " "in a #request method"
end
return false unless request.get?
url_string = url_for(options)
# We ignore any extra parameters in the request_uri if the
# submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
if url_string.index("?")
request_uri = request.fullpath
else
request_uri = request.path
end
if url_string =~ %r^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
else
url_string == request_uri
end
end
I don't really understand why they would have gone out of their way to make current_page? work only for GET requests, but at least now I know that that's the way it is.
You could create a new current_path? method in your ApplicationHelper:
def current_path?(*paths)
return true if paths.include?(request.path)
false
end
Pass in one or more paths and it returns true if any match the user's current path:
current_path?('/user/new')
current_path?(root_path)
current_path?(new_user_path, users_path '/foo/bar')
Or, you can create a new current_request? helper method to check the Rails controller + action:
def current_request?(*requests)
return true if requests.include?({
controller: controller.controller_name,
action: controller.action_name
})
false
end
Pass in one or more controller + action and it returns true if any match the user's current request:
current_request?(controller: 'users', action: 'new')
current_request?({controller: 'users', action: 'new'}, {controller: 'users', action: 'create'})
==UPDATE==
Ok, I decided to make using current_request? a little less verbose by not requiring that you type out the controller when you are trying to match multiple actions:
def current_request?(*requests)
requests.each do |request|
if request[:controller] == controller.controller_name
return true if request[:action].is_a?(Array) && request[:action].include?(controller.action_name)
return true if request[:action] == controller.action_name
end
end
false
end
Now you can do this:
current_request?(controller: 'users', action: ['new', 'create'])
I was having the same problem when using POST. My solution was to do something like this
def menu_item link_text, link_path
link_class = (request.original_url.end_with? link_path) ? 'active' : ''
content_tag :li, link_to(link_text, link_path), class: link_class
end
where link_path is just url_for(action: 'action', controller: 'controller')

Rails 3: Sortable Columns

I'm following Railscasts #228 in Rails 3.0.5 and ruby 1.9.2p180.
I have copied code near verbatim from the verbatim with the exception of changing the class name from Product to Player. I'm also skipping the last portion where Ryan adds arrows to denote the sort direction. I'm able to load the correct index page and see all of the desired URL's with the desired parameters (direction and sort), but nothing is actually happening on click. The URL is changing, but the page is not reloading.
Here is my code:
ApplicationHelper
def sortable(column, title = nil)
title ||= column.titleize
direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
link_to title, :sort => column, :direction => direction
end
PlayersController
def index
#players = Player.order(sort_column + ' ' + sort_direction)
end
private
def find_team
session[:team] ||= Team.new
end
def sort_column
Player.column_names.include?(params[:sort]) ? params[:sort] : "name_e"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
Thanks for your help!
Edit: As requested, HTML code. You can see that the link for Position is currently desc, as I am at: http://localhost:3000/players?direction=asc&sort=abb_pos. However, no actual sorting has occurred for this column, or any other column.
<th>Name</th>
<th>Team</th>
<th>Position</th>
<th>Height</th>
<th>Weight</th>
Nathan
I'd suggest doing this first thing:
def index
order = sort_column + ' ' + sort_direction
puts "-- order:'#{order}'"
...
end
Click the links and then look in server's console for that "--" output. Most probably there's a logical flaw somewhere that makes the actual compiled ORDER clause always be the same. Links themselves look perfectly okay. Unless there's a # character in the links somewhere, all clicks should work (i.e. the browser should reload the content).
As for the problem in general, there's a gem called handles_sortable_columns, which gets you sortable columns for no effort at all.
Alex
Found the issue. I had the following code in my player model:
Player.rb
default_scope :order => 'name_e'
As a result, the SQL search generated looked like this:
SELECT `players`.* FROM `players` ORDER BY name_e, avg_points desc