active record to hash inside itself - ruby-on-rails

So this is a bit of a silly one and is more lack of programming knowledge rather than anything ruby or rails specific.
If i wanted to turn an ordinary class into hash its not so bad. I already have one:
class CustomRequest
require 'json'
require 'net/http'
attr_accessor :url, :depth, :status
def initialize(url,depth)
#url = url
#depth = depth
end
def make_me_hash_and_send
#myReq = {:url => #url, :depth =>#depth}
myJsonReq = #myReq
puts myJsonReq
res = Net::HTTP.post_form(URI.parse('http://127.0.0.1:3008/user_requests/add.json'),
myJsonReq)
end
end
Simply generates the hash from the internal variables that are passed in the constructor. I want to do the same for active record but the abstractness of it isn't making it easy.
Lets say I have this class
def turn_my_insides_to_hash
#How do I take the actual record variables
# nd generate a hash from them.
#Is it something like
#myHash = {:myString = self.myString
:myInt => self.myInt }
end
I may be looking at this the wrong way. I know Outside of the class I could simply say
#x = Result.find(passed_id).to_hash
and then do what I want to it. But I would rather call something liks
#x = Result.send
(which turns the result's variables into hash and sends them)
I already have the send part, just need to know how to turn variables into hash from inside class.

You could try use JSON instead of YAML:
Result.find(passed_id).to_json
or
Result.find(passed_id).attributes.to_json
also you can use options like :except and :only for to_json method.
Result.find(passed_id).attributes.to_json(:only => ['status', 'message'])

record.serializable_hash
http://api.rubyonrails.org/v4.0.12/classes/ActiveModel/Serialization.html#method-i-serializable_hash
I write something more because SO ask me to do so.

Related

Overwriting default accessors with options

I am using Ruby on Rails 4 and I would like to know what could be the pitfalls when I overwrite default accessors. The Rails' Official Documentation says (in the initial lines):
The mapping that binds a given Active Record class to a certain
database table will happen automatically in most common cases, but can
be overwritten for the uncommon ones.
More, in that documentation there is the "Overwriting default accessors" section which makes me think that I can do it without any problem. What do you think about?
In my case I would like to overwrite attribute accessors in order to provide some options, something like this:
# Given my Article model has :title and :content attributes
# Then I would like to overwrite accessors providing options this way:
class Article < ActiveRecord::Base
def title(options = {})
# Some logic...
end
def content(options = {})
# Some logic...
end
end
# So that I can run
#article.title # => "Sample Title"
#article.title(:parse => true) # => "Sample *Title*"
#article.content # => "Sample description very long text"
#article.content(:length => :short) # => "Sample description..."
Maybe this is more Ruby than Rails, but will be the #article.title calling the title(options => {}) method or it will call the Rails attribute accessor that access the related database table column value?
Update (after commenting)
Since it seems that in the above code default accessors are not overwritten, is there a way to provide options for those accessors so to reach what I am looking for? If so, how?
#article.title #=> will call your method
#article.title(:parse => true) #=> will call your method
There is no method overloading in ruby if that is what you are looking for.
Looking closer at the official documentation I see where your code diverges.
You forgot "=" when defining your method.
class Foo < ActiveRecord::Base
def self.bar=(value)
#foo = value
return 'OK'
end
end
Foo.bar = 3 #=> 3
WARNING: Never rely on anything that happens inside an assignment method,
(eg. in conditional statements like in the example above)

How to apply attr_accessor for a variable in hash in Rails 3

I have some variables in a instance variable (for other methods can access the variable) which type is hash.
if I don't want all members in hash #iw2 applied attr_accessor
only #iw2[:dir] can be modified by others.
#iw2 ={}
#iw2[:dir] = "#{Rails.root}/#{ENV["module_handy_network_tools_src_path"]}"
#iw2[:prog_path] ="#{#iw2[:dir]}/#{ENV["module_handy_network_tools_prog_path"]}"
So I wrote that way,
attr_accessor :iw2[:dir]
But I got the error
TypeError (can't convert Symbol into Integer):
app/helpers/handy_network_tools_helper.rb:8:in `[]'
How to fix the problem, thanks in advance.
[2] pry(#<HandyNetworkToolsController>)> #iw2.class
=> Hash
Edit
When you find yourself having many methods with the same prefix (iw2 in this case), it is a sign that there's a hidden object in there. How about this? Better?
class Iw2
def initialize(hash)
#dir = hash[:dir]
#prog_path = hash[:prog_path]
end
attr_accessor :dir, :prog_path
end
class MyClass
def initialize
#iw2 = Iw2.new(:dir => "a rails path",
:prog_path => "some another rails path")
end
delegate :dir, :prog_path, :to => :#iw2
end
mc = MyClass.new
mc.dir # => "a rails path"
mc.prog_path # => "some another rails path"
Original answer
Well, attr_accessor doesn't work like that. You can always use old-fashioned getters/setters.
def iw2_dir
#iw2[:dir]
end
def iw2_dir=(dir)
#iw2[:dir] = dir
end
You can then implement your own attr_sub_accessor that will generate such methods for you.
attr_sub_accessor :iw2, :dir
attr_sub_accessor :iw2, :prog_path
(I think explicit getters/setters are better in this case)

What are the consequences of overriding Array.to_param within an ActiveResource based plugin

An active_resource based class:
Contact.search(:email => ['bar#foo.com','foo#bar.com'])
would produce this:
?email[]=bar#foo.com&email[]=foo#bar.com
The specific API that I'm working with requires this:
?email=bar#foo.com&email=foo#bar.com
So playing around I have found that:
ActiveResouce calls:
# Find every resource
find_every(options)
which calls:
# Builds the query string for the request.
def query_string(options)
"?#{options.to_query}" unless options.nil? || options.empty?
end
So if I update:
class Array
# Converts an array into a string suitable for use as a URL query string,
# using the given +key+ as the param name.
#
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
def to_query(key)
prefix = "#{key}[]"
collect { |value| value.to_query(prefix) }.join '&'
end
end
to this:
class Array
# Converts an array into a string suitable for use as a URL query string,
# using the given +key+ as the param name.
#
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
def to_query(key)
prefix = "#{key}"
collect { |value| value.to_query(prefix) }.join '&'
end
end
it works!! however I'm not particularly happy redefining Array.to_param because this may have unforeseen issues, especially as this plug in needs to work within rails.
Is there another way I can patch only my version?
I would definitely recommend NOT monkey patching an array method like that. If you only have a single model, could you override the search method?
class Contact
def self.search(options={})
super(options).gsub('[]','')
end
end
As this behaviour is standard through the API I'm using I was able to add this patch to my ActiveRecord::Base class.
def query_string(options)
begin
super(options).gsub('%5B%5D','')
rescue
end
end
Thanks to Beerlington for pointing me in the right direction for this.

How to obscure the id in a url (ruby on rails) [duplicate]

This question already has answers here:
How do I obfuscate the ids of my records in rails?
(6 answers)
Closed 7 years ago.
I have a web app made with Ruby On Rails. For now when I want to display an object I have to access the following page: http://mywebapp.com/object/1234 with 1234 the id of the object.
I would like to encode that object id and have the following result: http://mywebapp.com/object/5k (it is just an example).
How can it be done?
Many thanks,
Martin
All these converting methods are reversible, so IMHO if your object has some name or title or whatever, then the best way is adding a slug.
In such case add a new attribute :slug to your object, let automatically generate it's value from object name (or something else) on the model:
class MyObject
validates_format_of :slug, :with => /\A[a-z\-0-9]*\Z/
before_validation :generate_slug, :on => :create
def generate_slug
if self.slug.blank?
slug = self.name.mb_chars.downcase.normalize(:kd).to_s.gsub(/-/, " ").squeeze(" ")
slug = slug.gsub(/\s/, "-").gsub(/[^a-z\-0-9]/, "")
current = 1
self.slug = slug
while true
conflicts = MyObject.where("slug = ?", self.slug).count
if conflicts != 0
self.slug = "#{slug}-#{current}"
current += 1
else
break
end
end
end
end
end
then the URL can be http://mywebapp.com/object/my_object_slug, because in action you find the object via this slug:
class MyObjectController
def some_action
my_object = MyObject.find_by_slug(params[:slug])
...
end
end
Don't forget modify routes.rb:
match "object/:slug", :to => "my_objects#some_action"
You could probably do this with Base64 encoding (although if you're really trying to keep the internal id secret someone could probably guess you're using Base64 encoding and easily determine the id).
Your controller would need to look a bit like this
class ThingsController < ApplicationController
require 'base64'
def show
#thing = Thing.find Base64.urlsafe_decode64(params[:id])
end
def edit
#thing = Thing.find Base64.urlsafe_decode64(params[:id])
end
#These are just a couple of very simple example actions
end
Now actually encoding your URLs is going to be a little bit trickier - I'll look into it as it seems like an interesting problem (but I'm not making any promises).
Edit -
A bit of reading reveals that ActionView uses the to_param method in url_for to get the id of an object. We can override this in the model itself to encode the id like so
class Thing < ActiveRecord::Base
def to_param
Base64.urlsafe_encode64 self.id.to_s
end
end
Everything I've written here is conjectural. I haven't done this before or tested the code so I can't give any guarantee as to whether it will work or whether it will introduce unforeseen problems. I'd be very interested to hear how you go.

Accessing Rails Class/Model Methods

I am new to rails and am figuring out the best ways to write certain methods.
I am trying to write a method that belongs to a certain model and can be accessed without initiating an instance. So far I have this under my class PaymentNotification < ActiveRecord::Base
def url
url_for(:controller => 'payment_notifications', :only_path => false)
end
The problem here is that I need to do this to access the url
n = PaymentNotification.new
n.url
In my code, I want to be able to write PaymentNotification.url to access the method relevant to that model.
Maybe I am thinking about this the wrong way and someone can guide me. Basically, what I am trying to achieve is that each model can have its set of methods and attributes so that they all are organized and I know from the code which file each method is declared in, instead of just calling a
payment_notification_url
which may be located in any of the irrelevant initialization files. I saw helper methods but it seems like i still won't be able to use a dot syntax and will have to write something like "payment_notification_url" to access my url
Any ideas on the best way to go about doing this?
You need to define a class method via the self keyword.
def self.url
url_for(:controller => 'payment_notifications', :only_path => false)
end
Then you can use PaymentNotification.url
class A
def self.a
p "Class method"
end
def b
p "Instance Method"
end
end
A.a #Class method
#A.b #NoMethodError
a = A.new
a.b #Instance Method
#a.a #NoMethodError

Resources