rails method from multiple methods - ruby-on-rails

So I have this code in my Rails presenter(similar to Draper gem):
def title
h.link_to 'Favor', favor_path(#favor) + asked_or_published? + user_link
end
def asked_or_published?
if asked_favor?
h.content_tag(:p, "published by")
elsif published_favor?
h.content_tag(:p, "asked by")
end
end
def user_link
h.link_to #favor.favor_asker.firstname, h.user_path(#favor.favor_asker)
end
And I'm calling the title method in my view. The problem is that calling this method only returns the link_to 'Favor' part and not the rest. Why is that?
Thanks in advance!

It's a grouping priority issue, the + asked_or_published? + user_link bits are being added to the path generated by favor_path(#favor). Not sure if they're also being escaped correctly, but that is not relevant.
Replace this:
h.link_to 'Favor', favor_path(#favor) + asked_or_published? + user_link
with:
h.link_to('Favor', favor_path(#favor)) + asked_or_published? + user_link

Related

Rails if url params exist update data

I'm trying to update a few datetime columns if the url params exist, in order to send email notifications later. Columns are: first_expiration ,second_expiration, third_expiration inside the accounts table. In the url I'm passing a couple of params: the current registering users email and the plan_id.
This is the setup I have inside the devise registrations_controller:
Revised action:
after_action :set_expiration, only: [:create]
def set_expiration
if params.has_key?["plan_id"].present? == "nt127"
#first_expiration = DateTime.now + 152.days
#second_expiration = DateTime.now + 167.days
#third_expiration = DateTime.now + 177.days
current_client.account.update!(first_expiration: #first_expiration,
second_expiration: #second_expiration,
third_expiraton: #third_expiration)
elsif params.has_key?["plan_id"].present? == "mli90"
#first_expiration = DateTime.now + 335.days
#second_expiration = DateTime.now + 350.days
#third_expiration = DateTime.now + 360.days
current_client.account.update!(first_expiration: #first_expiration,
second_expiration: #second_expiration,
third_expiraton: #third_expiration)
end
end
def current_client
if cookies["email"].present?
User.find_by_email(cookies["email"])
end
end
But if I check the console the update is not working. No errors are poping up and generally nothing is happening in regards to the update.
Update 1
This is my url:
http://localhost:3000/transactions/new?email=test11%40gmail.com&plan_id=ntl127&price=150.0
and I'm passing the params like this:
<%= hidden_field_tag(:email, params["email"]) %>
<%= hidden_field_tag(:plan_id, params["plan_id"]) %>
<%= hidden_field_tag(:amount, params["price"]) %>
You added the after_action and the set_expiration to your RegistrationsController.
But if you followed common Rails idioms then your example URL which starts with /transactions/new would point to the TransactionsController.
Just move the method and the after_action to your TransactionsController and you will be fine.
Edit this
elsif params["plan_id"] == "mli90"
I would suggest you to use .update! instead of .update_attributes!

Quickly create 3 ruby objects

I am trying to create 3 objects in a loop like this...
3.times do |i|
#part + i.to_s = Part.create(part_number: "000#{i + 1}")
end
I get the error
NoMethodError: undefined method to_s=' for 0:Fixnum`
I think its obvious what I am trying to do? I'd like three parts (#part1/#part2/#part3) with part numbers 0001/2/3 after the loop runs.
As Roman already suggested, you should use an array.
However, to answer you question:
3.times do |i|
instance_variable_set("#part#{i + 1}", Part.create(part_number: "000#{i + 1}"))
end
Or even:
(1..3).each do |i|
instance_variable_set("#part#{i}", Part.create(part_number: "000#{i}"))
end

How can I pull in the Rails action or controller names into my Ruby Gem for use in a log file?

First question on here so go easy please. I am writing a gem for use in my rails application. The gem will simply print to a log file the information passed via the params from an action in the controller. I have this working up until the point where I would like for the report file to also print the name of the action from where the information is coming from. So example output would be:
Logged Details: date and time
Report from action: (Controller + actions name like) Profile.update and then the params information. I have it working to pull in the params information with the code below.
I have commented out the part where I thought would bring in the data for me. getting an error on it. Any advise would be much appreciated. Thanks.
# initializes file and writes-only at end of file if exists or creates new one
def self.open(filename)
#filename = File.open(filename,'a+')
end
# method to take in any amount of parameters and write to file
def self.usageLog (*items)
ReportLogger.open("UsageLogging.txt")
# string actionName = controllerContext.RouteData.values["action"].ToString()
#filename.print("Logged Details: " + Time.now.strftime("%d/%m/%Y %H:%M:%S") + "\n")
# #filename.print("Report Action: :" + actionName)
items.each do |item|
#filename.print(item)
end
#filename.puts( " -EndLog" + "\n" + " - - - - - - - - - - - - - - ")
end
Amended - I've played about with this but couldn't seem to get it working. I've changed the controller to call ReportLogger.usageLog(profile_params) so this should pull in all the params? I've amended the Gem code like below but it doesn't seem to want to pull in the controller details to the log.
# method to take in any amount of parameters and write to file
def self.usageLog(params)
ReportLogger.open("UsageLogging.txt")
# string actionName = controllerContext.RouteData.values["action"].ToString()
#controller_name = params["controller"]
#action_name = params["action"]
#other_params = params.reject do |k,v|
# %w(action controller).include? k
#end
#filename.print("Logged Details: " + Time.now.strftime("%d/%m/%Y %H:%M:%S") + "\n")
##filename.puts(controller_name)
##filename.print("Report Action: :" + controller_name)
controller_name = params[:controller]
#filename.puts(controller_name)
params.each do |param|
#filename.print(param.to_s + "\n")
end
#filename.puts( " -EndLog" + "\n" + " - - - - - - - - - - - - - - ")
end
Report log looks like:
Logged Details: 02/12/2015 13:11:11
["name", "Bradley"]
["phone_number", "087 6312683"]
["image", #, #original_filename="IMG_0001.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"profile[image]\"; filename=\"IMG_0001.jpg\"\r\nContent-Type: image/jpeg\r\n">]
["bio", "New feck, shit!"]
-EndLog
The params always contain the Controller name and the Action name:
def index
puts params
end
> {"controller"=>"home", "action"=>"index"}
So if you make your usageLog method accept the whole params hash, you can just access these, like:
def self.usageLog(params)
controller_name = params["controller"]
action_name = params["action"]
other_params = params.reject{|k,v| %w(action controller).include? k }
end
Then where ever you want to log from a controller, just do:
ReportLogger.usageLog(params)
Or if you want to pass in multiple arguments, you might call it this way:
ReportLogger.usageLog(params[:controller], params[:action], model_params, "anything else")
where model_params is your sanitized white list method for the model you are dealing with.
Then you would define your method like:
def self.usageLog(controller_name, action_name, *items)
....
items.each do |item|
#filename.print(item.to_s + "\n")
end
end

routing and searching a db ruby

I want to retrieve all the tweets that have a certain hashtag in them.
At first I add the hashtags in my 2 tables :
def add_hashtags(tweet)
tweet.content.scan(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/){ |tag|
#allhashes = Hashtag.all
#hash = Hashtag.find_by_name(tag[0].strip)
unless #hash
#hashtag = Hashtag.new(name: tag[0].strip)
#hashtag.save
#hashrel = Hashrelation.new(tweet_id: tweet.id, hashtag_id: #hashtag.id)
#hashrel.save
else
#hashrel = Hashrelation.new(tweet_id: tweet.id, hashtag_id: #hash.id)
#hashrel.save
end
}
end
then I want to route to the show method of tweet controller :
get 'tweets/show/(.:format)' => 'tweets#show', as: :hashtag
The links in the hashtags are as follows:
def twitify(tweet = '')
tweet.gsub(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/) do |tag|
" " + link_to("#{tag.strip}", hashtag_path(tag.strip), {:name => tag.strip})
end.html_safe
end
And finally the show method of the tweet controller is :
def show
#hashtag = Hashtag.find_by_name(params[:name])
#tweet_ids = Hashrelation.find_by_hashtag_id(#hashtag.id)
#feed_items = Tweet.find_by_id(#tweets_ids.id)
end
When I click on the link I get :
undefined method `id' for nil:NilClass
which means that params[:name] is either nill or it isn't like the one I have in the DB.
Could you guys help me figure this out ?
The link I see that is called is 'http://localhost:3000/tweets/show/.%23dadawea' which means I have extra things why would I ?.
I would do the following
def add_hashtags(tweet)
tweet.content.scan(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/).flatten.each do |tag|
hashtag = Hashtag.where(name: tag.strip).first_or_create
Hashrelation.create(tweet_id: tweet.id, hashtag_id: hashtag.id)
end
end
Then change the twitify method to look like
def twitify(tweet = '')
tweet.gsub(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/) do |tag|
" " + link_to("#{tag.strip}", hashtag_path(name: tag.strip))
end.html_safe
end
And the show method
def show
#hashtag = Hashtag.find_by_name(params[:name])
#tweet_ids = Hashrelation.where(hashtag_id: #hashtag.id).pluck(:id)
#feed_items = Tweet.where(tweet_id: #tweets_ids)
end
This should be what you are looking for. Now for whats changing:
Removed Duplicate logic in the add_hashtags to use create instead.
twitify method is passing name as an html option not a url option so I fixed that. Right now it thinks you want to set the format to the name of the hashtag and name the link the name of the hashtag**
show method is using find_by which will only return a single result not what you wnat for tweet_ids so i changed it to where clause and just grabbed the ids. Then changes feed_items to search Tweet for all tweet_ids in the Array.
To strip the # just use tag.strip[1..-1]

HTML escaped in Rails 3

I have a method call in my view like this
<%= Navigation.with(params) do |menu|
if current_user && current_user.can_verify?
menu.item("Listings", manage_listings_path())
menu.item("Listing changes", needing_change_approval_manage_listings_path())
menu.item("Flagged Items", flagged_manage_listings_path())
menu.item("Transfers", manage_listing_transfers_path())
menu.item("Reviews", manage_listing_reviews_path())
end
if current_user && current_user.admin?
menu.item("Log", manage_verifications_path())
menu.item("Indexer Compensations", manage_compensations_path())
menu.item("Users", manage_users_path())
end
end%>
that splits out the below string
"<li>Listings</li> <li>Listing changes</li> <li>Flagged Items</li> <li>Transfers</li> <li>Reviews</li> <li>Log</li> <li>Indexer Compensations</li> <li>Users</li>"
I just get this string in my page. I wanted them to be menus nicely styled by CSS. I am just getting the above raw text in my page. How do I convert this string to be treated as HTML by the browser.
Please help
Here is the navigation class
class NavigationMenu < ActionView::Base
def initialize(params)
#params = params
end
def item(title, path, options={})
#items ||= Array.new
unless (route = Rails.application.routes.recognize_path(path,:method => options[:method]|| :get))
raise "Unrecognised path #{path}, are you sure it's in routes.rb?"
end
#items << content_tag(:li, link_to(title,path, :class => (#params[:controller] == route[:controller] && #params[:action] == route[:action])? 'active' : nil))
end
def output
return '' if #items.blank?
content_tag(:ul, #items.join("\n"), :id => 'navigation')
end
end
class Navigation
def self.with(params, &block)
menu = NavigationMenu.new(params)
yield menu
menu.output
end
end
You have to add a call to the raw method:
<%= raw ... %>
This is necessary, because in Rails 3 every string is escaped by default, unless you use the raw method.
It's like an inverse of the h method in Rails 2, where every string is unescaped by default, unless you use the h method.
Example:
This code in Rails 2...
<%= h "String which must be escaped" %>
<%= "String which must be output raw %>
... must be this in Rails 3:
<%= "String which must be escaped" %>
<%= raw "String which must be output raw %>
(Although an additional call to h doesn't do any harm in Rails 3)
You need to append .html_safe to the string - this will stop rails from escaping it when it's time to output text. Probably best to put it in the item method that you call repeatedly.
I recently wrote an article regarding XSS protection in Rails 3 when upgrading from Rails 2:
http://developer.uservoice.com/entries/upgrading-to-rails-3-printing-escaped-strings
The idea is to hook code to printing HTML so that we can determine when we are actually printing something we don't want to:
module ActionView
module Helpers
module TextHelper
def simple_format_with_double_escape_reporting(*args)
HtmlDoubleEscapeReporter.assert_sane(simple_format_without_double_escape_reporting(*args))
end
alias_method_chain :simple_format, :double_escape_reporting
end
module TagHelper
private
def content_tag_string_with_double_escape_reporting(*args)
HtmlDoubleEscapeReporter.assert_sane(content_tag_string_without_double_escape_reporting(*args))
end
alias_method_chain :content_tag_string, :double_escape_reporting
end
module UrlHelper
def link_to_with_double_escape_reporting(*args, &block)
HtmlDoubleEscapeReporter.assert_sane(link_to_without_double_escape_reporting(*args, &block))
end
alias_method_chain :link_to, :double_escape_reporting
end
end
end
Method HtmlDoubleEscapeReporter.assert_sane can be written, for example, like this:
class HtmlDoubleEscapeReporter
def self.assert_sane(str)
if (str.match(/<[a-z]/) || str.match(/&(quot|rarr|larr|amp|#)/)) &&
!str.match(/looks something you do not want to print/
send_problem_report('#{str}' looks something you do not want to print")
end
return str
end
end
Here, 'looks something you do not want to print' is used to prevent the possibility of infinite loops. The line send_problem_report('#{str}' looks something you do not want to print") can be replaced with a call to "debugger" (from ruby-debug gem) so that you are able to check the backtrace and see where the problem is coming from.
Here is the new class. At last... I got that bug.
class NavigationMenu < ActionView::Base
def initialize(params)
#params = params
end
def item(title, path, options={})
#items ||= Array.new
unless (route = Rails.application.routes.recognize_path(path,:method => options[:method]|| :get))
raise "Unrecognised path #{path}, are you sure it's in routes.rb?"
end
#items << content_tag(:li, link_to(title,path, :class => (#params[:controller] == route[:controller] && #params[:action] == route[:action])? 'active' : nil))
end
def output
#items = #items.join("\n").html_safe
return '' if #items.blank?
content_tag(:ul, #items, :id => 'navigation')
end
end
class Navigation
def self.with(params, &block)
menu = NavigationMenu.new(params)
yield menu
menu.output
end
end

Resources