My models are:
class Node
include Mongoid::Document
end
class PhysicalServer < Node
embeds_many :network_interfaces
end
class NetworkInterface
include Mongoid::Document
embedded_in :physical_server
end
If I do:
server.network_interfaces.build()
server.save!
when I check database, I will see 2 NetworkInterface embedded documents with duplicate ids.
However if I do:
server.network_interfaces.create()
it'll work correctly (only 1 embedded document created).
Is it a bug in Mongoid, or there is something wrong with my code?
I'm using Ruby1.9.3 + Rails 3.2.9 + Mongoid 3.0.13
Not quite sure what the issue is "yet", but I was having the same issue which I have a workaround for the time being.
By doing a forced new lookup in my controller's update action, I was able to get rid of the '$pushAll' creating a duplicate on each call to update. I have a feeling it has something to do with Mongoid's build-up of atomic operations; using a new object simply just removes the 'build' action.
I've created a gist of the issue (hopefully making it possible to re-create both the failing scenario and a workaround: https://gist.github.com/jsmestad/d0103ba0197df9f4505b)
Related
I am looking to create a feature whereby a User can download any available documents related to the item from a tab on the PDP.
So far I have created a custom record called Documentation (customrecord_documentation) containing the following fields:
Related item : custrecord_documentation_related_item
Type : custrecord_documentation_type
Document : custrecord_documentation_document
Description : custrecord_documentation_description
Related Item ID : custrecord_documentation_related_item_id
The functionality works fine on the backend of NetSuite where I can assign documents to an Inventory item. The stumbling block is trying to fetch the data to the front end of the SCA webstore.
Any help on the above would be much appreciated.
I've come at this a number of ways.
One way is to create a Suitelet that returns JSON of the document names and urls. The urls can be the real Netsuite urls or they can be the urls of your suitelet where you set up the suitelet to return the doc when accessed with action=doc&id=_docid_ query params.
Add a target <div id="relatedDocs"></div> to the item_details.tpl
In your ItemDetailsView's init_Plugins add
$.getJSON('app/site/hosting/scriptlet.nl...?action=availabledoc').
then(function(data){
var asHtml = format(data); //however you like
$("#relatedDocs").html(asHtml);
});
You can also go the whole module route. If you created a third party module DocsView then you would add DocsView as a child view to ItemDetailsView.
That's a little more involved so try the option above first to see if it fits your needs. The nice thing is you can just about ignore Backbone with this approach. You can make this a little more portable by using a service.ss instead of the suitelet. You can create your own ssp app for the function so you don't have to deal with SCAs url structure.
It's been a while, but you should be able to access the JSON data from within the related Backbone View class. From there, within the return context, output the value you're wanting to the PDP. Hopefully you're extending the original class and not overwriting / altering the core code :P.
The model associated with the PDP should hold all the JSON data you're looking for. Model.get('...') sort of syntax.
I'd recommend against Suitelets for this, as that's extra execution time, and is a bit slower.
I'm sure you know, but you need to set the documents to be available as public as well.
Hope this helps, thanks.
I have the following models:
class User
include Mongoid::Document
embeds_one :courier, class_name: "Users::Courier"
validates_associated :courier
accepts_nested_attributes_for :courier
end
module Users
class Courier
include Mongoid::Document
embedded_in :user
after_create :foo
def foo
puts "courier created"
end
end
but this callback is only run if i call save directly on the courier object, not when i save the parent object.
Thus having a nested form and a controller that creates the user including the courier does not run the create callback of the courier.
The mongoid documentation says that this is by design:
Callbacks are available on any document, whether it is embedded within another document or not. Note that to be efficient, Mongoid only fires the callback of the document that the persistence action was executed on. This is that Mongoid aims to support large hierarchies and to handle optimized atomic updates callbacks can't be firing all over the document hierarchy.
But how can i write code that gets executed whenever a courier is created? In my case i cannot run the code in the user's after_create callback, because there are users that do not have the embedded document courier. But when a courier gets added i want to run a callback.
Whats the best option to do so?
found the answer:
embeds_one :courier, class_name: "Users::Courier", cascade_callbacks: true
I have one document embedded in another in Mongoid.
class A < B
include Mongoid::Document
embeds_one :shipping_address, class_name: 'Address'
I have, in my case, omitted the inverse relation:
class Address
# embedded_in :A
Why is it, that although the API works fine and completely as expected:
address = A.address
address.zip = 1234
a.changed? #true
address.save
a.changed? #false
The document is not actually saved?
If i return the embedded_in statement, the save actually works fine.
My understanding of the Mongoid source is not the best so don't kick me too hard mods.
I assume that Mongoid is similar to ActiveRecord in this regard. With ActiveRecord, defining a :has_many does not change the parent object but includes methods for accessing the child. belongs_to on the other hand pulls methods for managing foreign keys.
Looking at the source code for Mongoid it seems that persistence is called from the embedded class to the parent and not the other way around (source). Removing the embedded_in would remove the additional methods for inserting the child into the parent.
Feel free to correct me if I am way off :)
While you can gain a lot when you choose to embed documents in MongoDB, you do give up the ability to query everything outside of the context of the parent. If you want to be able to work with Address documents independently, outside of the context of the parent document, you should link documents with has_many instead of embedding with embeds_many. This comes with it's own set of pros and cons.
If you choose to embed documents, you do specify embedded_in in the model and you access the embedded documents like this:
a = A.new # Parent document
a.addresses # Embedded Address documents
( Documentation Reference )
I'm starting in the big wooly world of Ruby on Rails and i'm trying to get my head around scaffolds and models. (cue, I'm a designer)
I use the rails generate scaffold command
rails generate scaffold Lesson title:string description:text
But is it possible to update the Lesson table with new key, values with rails?
I tried:
rails generate model Lesson title:string description:text dtstart:datetime
But when I run the db:migrate it fails and the only way around I know of to do that is to delete all of the scaffold and regenerate it.
I'm sure there must be an easier solution :)
I think (but im not sure, that it is because of the db/development.sqlite3 file that is not updated, when I delete the content by hand it then run the bd:migrate) is there a way to have evrything updated at once?
I don't think there is a way to do what you describe - generally if you want to add new fields to a model, you want to generate a migration:
rails g migration AddStartToLesson
Then open the migration file and add the code that will add those fields. It will probably end up looking something like this:
class AddStartToLesson < ActiveRecord::Migration
def self.up
add_column :lessons, :start, :datetime
end
def self.down
remove_column :lessons, :start
end
end
And you'll have to update some of the views - probably _form.html.erb, to get the form field to enter that data, and index.html.erb and show.html.erb to display it. (they're probably in app/views/lessons/)
I think you must also update (in rails 5 at least) your lesson_params in lessons_controller.rb in order to allow the new parameters to be passed from the view to the model.
I am pretty new to Django and just got a job that involves maintaining and adding features to a site I did not design, so I am still kind of confused about the structure and what not of the project. The site is using South for database migrations and I've got a hang of using it to add new applications to the project. The trouble I am having now is that I need to delete a certain field in a model because it is no longer needed and on the admin page it is required to be filled out. From my understanding of Django so far it appears to be a custom field. It is defined like this in its own separate library application(still not sure if thats the right lingo).
class Genre(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return u"%s" % self.name
Here is the models that uses the custom field if that helps out any.
class Entry(models.Model):
artist = d51fields.ForeignKey(Artist, instantiate_fn=instant_artist)
album = d51fields.ForeignKey(Album, js_methods=['match_artist_and_startswith'], instantiate_fn=instant_album)
track = d51fields.ForeignKey(Track, js_methods=['match_album_and_startswith'], instantiate_fn=instant_track)
genre = models.ForeignKey(Genre)
submitted = models.DateTimeField(auto_now_add=True)
is_rotation = models.BooleanField()
dj = models.ForeignKey(DJ)
show = models.ForeignKey(Show, null=True, blank=True)
objects = EntryManager()
def __unicode__(self):
return "%s [%s]" % (self.artist, self.track)
class Meta:
verbose_name = "entry"
verbose_name_plural = "entries"
I've looked at the documentation for migrating custom fields but it is all really confusing for me, so I am looking for some more help. I just want to get rid of the table holding the Genre field and clean up the dependencies with the foreign keys associated with it. Do you think I should write some custom rules for South and use a migration or just try and do it manually in Postgresql. I tried doing it with just Postgres and I failed miserably.
Any guidance would be greatly appreciated. If you want more info about the situation just ask and I can add it to the post. I have a feeling there is a lot of dependencies I will have to deal with, but hopefully there is a simple fix.
Also if some one knows how to get a good view of the database structure that would be great.
Thanks so much. All of you guys are great.
Edit1
Here what I got when I removed the ForeignKeys and then ran
manage.py schemamigration logs --auto
! Cannot freeze field 'logs.entry.artist'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.album'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.track'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! South cannot introspect some fields; this is probably because they are custom
! fields. If they worked in 0.6 or below, this is because we have removed the
! models parser (it often broke things).
I am not totally sure what sort of action I should take next. I looked into the South documentation and it wasn't too clear about how to write the rules for migrating things like this.
I don't see any custom field anywhere in the code you posted. All I see is two models, all containing standard fields shipped with Django.
If I understand correctly, you can just delete all ForeignKey references to your Genre model. Then run ./manage.py schemamigration <yourappname> --auto. This will ask you for a default value for the genre field in the Entry model, provide an ID of some kind. (This is because migrations can be applied both forwards and backwards, so if you try to undo the migration, this is the value that will get inserted in all your model instances.)
Finally, just applying the migration should make it happen: ./manage.py migrate <yourappname>.
After that you should be safe to drop the table storing your Genre model.
Be sure to try this on a development server though, just to make sure it doesn't blow up. (-;