so i need to create an image that belongs to my model (string with the url of the image) in the models create method.
the problem is, that this image is a QR-Code that should contain the url of the object that gets created.
but the URL (of course) is unknown in the create method because no id exists at that point for the given object.
any ideas how to solve this problem?
I don't see an obvious way of doing this, beyond using a non id column within the URL (e.g. make a call to generate a UDID/GUID, and use that in the url http://mysite.com/obj/#{udid}), or saving in two stages, using the after_create callback to set the image once the record has been saved:
class MyModel < ActiveRecord::Base
after_create :set_image
def set_image
if image_attribute == nil
image_attribute = generate_a_qr_code(self)
self.save
end
end
end
Use two-pass saving :-)
def create
model = Model.new params[:model]
if model.save
# at this point you have an id
model.qr = generate_qr model
model.save
# proceed as usual
end
end
This is for traditional databases with auto-increment column as primary key. In some databases, keys are generated using sequences that you can query to get a new value (before saving your object). In some databases (MongoDB) keys can be generated on the client completely.
Related
In my project, I have a model called PaymentCondition and another called PaymentPortion.
PaymentCondition has_many payment_portions and PaymentPortion belongs_to payment_condition.
When I create a new PaymentCondition, I have this method that creates n payment_portions. Being n the value of a :amount attribute from PaymentCondition.
If I create a new PaymentCondition with amount: 2, for instance, I'd have 2 payment_portions.
So far, so good.
My problem:
I'm using a nested form to this view, so I can edit everything at once.
PaymentCondition has a attribute called catchments.
PaymentPortion has a attribute called catchment.
Before submiting this form, I'd like to check if the sum of PaymentPortion.catchment is equal to PaymentCondition.catchments. If not, I must raise an error.
As for now, I can't get the new values of PaymentCondition before saving it...
I'm doing this inside payment_conditions_controller:
before_update :check_catchments
def check_catchments
errors.add(:catchments, "Values must check") unless catchments_check? || new_record?
end
def catchments_check?
catchment == portion_catchments
end
def portion_catchments
payment_portions.sum(:catchments)
end
Using sum(), I get only the values that are on the database. What I need are the values that are being send...
Is there a way to do so?
Thanks in advance.
May be working directly in the controller is an option? You can use methods like 'build' or 'first_or_initialize' to get\create AR objects. And then just validate them in the controller and save the data if necessary.
Is there any way to initialize a record from session. for e.g I have a organization object and I put this in session object like
session[:organization] = organization
Now I made a custom method current_organization (I know about devise) like
def current_organization
Organization.new(session[:organization])
end
This will return organization object. My organization belongs_to a team a devise model and team has_many :organizations but when I call
current_team.organizations.includes?(current_organization)
in view. It is returning false even if it is included in team's organizations but doing this
current_team.organizations.reload.includes?(current_organization)
is returning true. I set the session variable with organization object before calling view where i am using above method. Is there any thing which I missed like I am not able to figure out the reason for not returning true even it is included?
Try saving the record first.
Until you save it into the database, it is likely not to show up when you query for the team's organization children.
session[:organization_id] = organization.id
def current_organization
Organization.find session[:organization_id]
end
Ok after some googling i found that instead of using
Organization.new(session[:organization])
I should use
Organization.instantiate(session[:organization])
From apidock I found that
instantiate(attributes, column_types = {}) public
Given an attributes hash, instantiate returns a new instance of the
appropriate class. Accepts only keys as strings.
For example, Post.all may return Comments, Messages, and Emails by
storing the record’s subclass in a type attribute. By calling
instantiate instead of new, finder methods ensure they get new
instances of the appropriate class for each record.
Suppose I deleted a document or subdocument in mongodb. Can I create document / subdocument with the same _id as the deleted one? In this case, we assume, we cannot do update operation, just delete and create.
For example using Mongoid (Rails gem for mongodb) :
We have Person Model
class Person
include Mongoid::Document
field :a, :type => String
embeds_many :personattributes
end
class Personattribute
include Mongoid::Document
field :myattribute, :type => String
embedded_in :person
end
And in my Rails controller
class MyController < ApplicationController
...
#the_attributes=#person.personattributes.entries
...
#controller will render page, an instance variable #the_attributes will be available as JSON in clientside
end
Then user does some client side data modifications. They can add 1 or more personattributes to that person data. They can do some changes on its attributes. They can delete some also.
All in client side.
Then by AJAX call, user sends the modified data back in JSON format like
[{_id:"5253fd494db79bb271000009",myattribute:"test"},{...},...]
The retriever in controller retrieves the data
Then totally replace the attribute list inside person with the new one. Total deletion and insertion, no update.
class MyController < ApplicationController
...
#person.personattributes.delete_all #delete all attributes a #person has
attributes=params[:attributes]
attributes.map {|attr|
Personattribute.new(:_id => Moped::BSON::ObjectId.from_string(attr["_id"].to_s), :myattribute => attr["myattribute"])
}
#person.personattributes=attributes
#person.save
...
end
Can I do this? It simply means, delete all, and insert all and reuse the _ids.
If not, I will be happy to get some advice on a better approach on this.
I can't do upsert since the deleted documents will need another loop to handle.
Thank you
Yes, you can do it but I would recommend you not to do that. It seems to have lots of security issues if someone modifies the array manually
I could send:
[{_id:"5253fd494db79bb271000009",myattribute:"test_modified"},{...},...]
or even:
[{_id:"my_new_id_1",myattribute:"test_modified"},{...},...]
which would raise an exception
Moped::BSON::ObjectId.from_string "my_new_id_1" #=> raises an Exception
Try something like:
attributes=params[:attributes]
attributes.each do |attr|
#person.personattributes.find(attr["_id"]).myattribute = attr["myattribute"]
#or #person.personattributes.find(attr["_id"]).try(:myattribute=,attr["myattribute"])
end
Probably in a future you want to change the action and send just the modified personattributes in the array instead of all the personattributes. What would you do then if you delete_all and rebuild personattributes with just the sent personattributes?
EDIT
This handles personattributes updates. Create or delete personattributes should go in different actions:
Create action
#person.personattributes.push Personattribute.new(my_attribute: params[:my_attribute])
Delete action
#person.personattributes.delete(params[:personattribute_id])
Yes, you can keep using the same _id. They just need to be unique within a collection -- and that's only true for the document's _id.
Any ObjectId you might use elsewhere in an another field in a document (or in a subdocument) doesn't need to be unique, unless you've created an index where it must be unique.
I have two tables:
stores
raw_stores_data
The raw_stores_data is received from a third party daily.
I'd update certain fields of the stores model if those fields have been modified for that record in raw_stores_data.
Currently I have a bunch of conditional statements that check each of those fields. Is there any better way to code this?
new_data = raw_stores_data.all.select do |item|
item.store_id.present?
end
new_data.each do |item|
if item.field1 != item.stores.field1
...
...
...
# update record with hash of fields to update created above
end
You could add an association and special mutators to the 'raw' model that know how manipulate the 'stores' object. This serves to keep the model code in the model. Thin controller, comprehensive models, etc.
class Store < ActiveRecord::Base
has_one :raw_stores_data
end
class RawStoresData < ActiveRecord::Base
belongs_to :store
def field1=(value)
store.field1 = value
store.save!
field1 = value
end
end
I'm hand waving at some of the details, and you might want to reverse the direction of the association or make it go both directions.
EDIT:
You would use this as such:
raw_data = RawStoreData.find(param[:id]) # or new or however you get this object
raw_data.field1 = param[:field1]
The act of assigning will use the 'field1=' method, and make the change to the associated store object. If you're worried about saving unnecessarily, you could conditionalize in that method to only save if the value changed.
I hope this is clearer.
Is this any possible?
I'd like to have something like
User.avatar.to_url
which would then print the full URL address for the user's avatar image.
=> "http://url.com/images/avatars/1262694724.jpeg"
Of course, the avatar attribute would be an existing column on the users table which contains a long integer.
The to_url method im thinking on would be defined as:
def to_url
"http://url.com/images/avatars/#{self}.jpeg"
end
If avatar is an attribute (as opposed to another model/association) then you're going to save yourself a world of trouble by just doing:
def avatar_url
"http://url.com/images/avatars/#{avatar}.jpeg"
end