Mongoid has_many relationship causes Rack cookie error in Sinatra - ruby

Writing an application using Mongoid 3.1 and Sinatra in Ruby 1.9.3. I have a model called Order that has_many Items. Whenever I try to append an Item to an Order.items, I run into problems. I have the following route, summed up slightly:
order = session[:user].get_order(Time.now)
order.items << Item.new
order.save
"Hi, mom!" # Garbage page so that I know nothing else is called.
Doing that once is okay; doing it twice causes the following error:
Warning! Rack::Session::Cookie data size exceeds 4K.
Warning! Rack::Session::Cookie failed to save session. Content dropped.
I've been banging my head against the wall trying to get it to stop doing this. Why is the session loading all my items? Am I not using the has_many relationship correctly?

Your User model probably has_many :orders. Ruby is probably calling Marshal.dump to dump your user object into the cookie. You can imagine this might get huge. You should do the following:
Only store the user_id in the session.
Store your session server-side instead of in the cookie.
You'll need to use different middleware to store your session server-side. See this page for an example of storing your session in memcache. Since you're already using mongo, you could use Rack::Session::Mongo.
Even though you're not using Rails, the Rails guide on session security is useful reading. [link]

Related

Rails Active Admin unpermitted parameter

I have some problem/issues with active admin on rails, specifically unpermitted params error:
existing active admin parameter
here is the existing active admin parameter
model associated with the main model im working with
As per active admin documentation I should be doin right, as the other attributes for dispatch_information model is being accepted by rails and I was able to read and write with out any issues. Just with this recently added attribute "custom_attorney". Associations already set. and with out declaring an attr_accessor on model file it says this error
No method error
as it seems it cannot read or detect the column that I added for dispatch_information model, while in my console its already there.
When I add it with attr_accessor "while it should not, just to proceed on the form page" then I fill in the attributes need, im getting weird stuff in my console
Console view
as you can see it seems it being added inside efile_order hash instead of dispatch_information_attribute hash, and at the bottom part of the image you can see it says unpermitted parameters, even I added it inside the correct attribute block, we can also notice that the other attributes pf dispatch_information works really fine, just this recently added custom_attorney attribute. I already did everything like migration and other stuff.
Form Input
here is my form where we can see that input is on the same block where dispatch_defendant and dispatch_plaintiff is included and those two attribute works fine as well.
I really dont know what I missed here. TIA
The problem is that custom_attorney should be nested under dispatch_information_attributes you have it in the wrong place so it's unpermitted.
The correct way to do that is to add a block for those attributes and nest them.
- f.simple_fields_for :dispatch_information do |d|
- d.input :custom_attorney, :input_html => { id: 'new-attorney' }
It may be a good idea to provide an object for dispatch_information if you care for existing data. Assuming your ivar is named #e_filling_order then you should have the following.
- f.simple_fields_for :dispatch_information, #e_filling_order.dispatch_information || #e_filling_order.build_dispatch_information do |d|

Caching dataset results in Sequel and Sinatra

I'm building an API with Sinatra along with Sequel as ORM on a postgres database.
I have some complexes datasets to query in a paging style, so i'd like to keep the dataset in cache for following next pages requests after a first call.
I've read Sequel dataset are cached by default, but i need to keep this object between 2 requests to benefit this behavior.
So I was wondering to put this object somewhere to retrieve it later if the same query is called again rather than doing a full new dataset each time.
I tried in Sinatra session hash, but i've got a TypeError : can't dump anonymous class #<Class:0x000000028c13b8> when putting the object dataset in it.
I'm wondering maybe to use memcached for that.
Any advices on the best way to do that will be very appreciated, thanks.
Memcached or Redis (using LRU) would likely be appropriate solutions for what you are describing. The Ruby Dalli gem makes it pretty easy to get started with memcached. You can find it at https://github.com/mperham/dalli.
On the Github page you will see the following basic example
require 'dalli'
options = { :namespace => "app_v1", :compress => true }
dc = Dalli::Client.new('localhost:11211', options)
dc.set('abc', 123)
value = dc.get('abc')
This illustrates the basics to use the gem. Consider that Memcached is simply a key/value store utilizing LRU (least recently used) fallout. This means you allocate memory to Memcached and let your keys organically expire unless there is a reason to manually expire the key.
From there it becomes simply attempting to fetch a key from memcached, and then only running your real queries if there is no match found.
found = dc.get('my_unique_key')
unless found
# Do your Sequel query here
dc.set('my_unique_key', 'value_goes_here')
end

How to create an empty activerecord object in rails 4?

I am trying to develop a Rails application for QuickBase for which there is no adapter. I checked online for the QuickBase adapter but it is not working as it is for a very old version of rails and the author told me that he no longer supports it.
I want to be able to use the Active Record and the associated concepts of a typical rails application, but intervene and modify how the create, update and show actions work. I have created the application to create a new record successfully. However, when I want to be able to edit the record, I have first modified the edit action to go to my own database and get the data into an active record object.
To create an empty Active Record I said $user = User.new
Then I populated all the attributes with the data from my custom database. But the form still shows the Create User button, instead of Update User button. Apparently, I guess this is because the persist? method is returning false as this is a "new" object. But I know this is not a new one. So how do I influence the #user object to think it is a persistent one?
Alternatively, is there a way I can create the blank #user object without the new function?
I have checked all over the place, but couldn't find any clue on how to accomplish this. Thank you so much for your help.
You can try calling #user.disconnect! after your call #user = User.new, which will keep ActiveRecord from trying to write to the database, but I'm not sure that will solve your problem.
The larger problem is that you're trying to fit a square peg into a round hole here. The entire point of ActiveRecord is to abstract the connection to a database. So without a database, what's the point?
I think your best solution would be to write your own QB adapter. It may not be as difficult as you think, since you already seem to know how to read/write to the database.
You can read more about how to do that here: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/AbstractAdapter.html

Rails 4: Append to a "has_many" relation without saving to DB

In Rails 3 one can do things like some_post.comments.append(some_comment) where some posts is an instance of a model that "has_many" comments.
The problem I'm facing in Rails 4 is that the append method now saves to DB (like push and << ) and I need to just "append" without saving the appended object to the DB.
How do we achieve that in Rails 4? I can't use some_post.comments.build(some_comment.attributes) because I need to preserve the other relations already present in the some_comment instance.
It's oddly difficult to do this elegantly in Rails. This is the cleanest way I've found:
post.association(:comments).add_to_target(comment)
You could do:
class Post < ActiveRecord::Base
has_many: comments, autosave: false
...
end
Then << will just append and not save.
You can do it without using reflection on the association:
post.comments.build(
attr_1: value_1,
attr_1: value_2,
# Other comment attributes
)

How can I work with attributes of a belongs_to relationship in Rails 3.1?

I have a couple of basic Rails problems that I'm having trouble finding relevant current (Rails 3+) information on. Here is the first:
How do I access attributes of a parent object to display them in the view? I have the following models:
class Site < ActiveRecord::Base
has_many :devices
class Device < ActiveRecord::Base
belongs_to :site
I'm using regular restful routes (do nested resources come into play here?) and the standard find methods in the Devices controller. In the view for devices I want to display the name of the site that owns the device, but everything I try gives me errors. How can I access and display the Site.name value for a given device?
Thanks in advance for your help!
It's hard to know what's wrong without seeing what you're trying. Compare the working example below with your technique. But first check that your device actually has a site, as explored here: Rails belongs_to association, can't access owner's attributes when part of a collection?
Try this in your rails console:
site = Site.create(:name => "Boston")
device = Device.create(:name => "hackatron")
site.devices << device
device.site.name #=> "Boston"
You can see my full output in this gist
If that doesn't help pinpoint where your error is, please share some code and the errors you're seeing.

Resources