Mongoid: Changing the order of documents in an embeds_many relation - ruby-on-rails-3

I have a mongoid document which embeds other documents with a relation like
this:
embeds_many :blocks
Creating new blocks works fine, but I cannot manage to change the
order of existing embedded documents. For example I have three
embedded blocks and I want to move the last one to the first
position.What's the correct way to do that?

I had to deal with this with mongoid's recursively_embeds_many feature, but it's essentially the same. There's nothing wrong as far as I can tell with literally rewriting the document. Write a model method to do something like:
def reverse_blocks
reversed_blocks = blocks.to_a.reverse
blocks.clear
reversed_blocks.each do |b|
blocks.create b.attributes
end
save
end
That's not great code above, but it gives you an idea of how to do what you want to do. I'm not thrilled with having to go through that just to reorder stuff in an array, but there it is.

I think, that really correct way is make in your embedded docs field "weight" and query them with asc(:weight) or desc(:weight). You don't rely on the order of persisted non-embedded docs, so you shouldn't in embedded.
But if you urgently need to make this, your embedded docs in mongoid are just array, so you can do such way:
doc.embedded_docs = [doc.embedded_docs.last] + doc.embedded_docs[0..-2]

Related

Elasticsearch search analyzer

I am playing with indexing an articlenumber in Elasticsearch.
Here i provide a working example:
https://found.no/play/gist/557202b3542be157d813
i dont understand why i get a different score if i change the value for "product_number.search"
if i change the value from "ak454" to "ak 454" the score changes.
i thought that if i am using a search_analyzer the value "ak 454" will be transformed to "ak454" (its mapped using the searchable_id).
you can also look at the analyses tab to see my tokenizer:
https://found.no/play/gist/557202b3542be157d813#analysis
thanks.
The term-query (and filter) does not do any text analysis.
The match-query does, and can achieve what you want.
I adapted the example: https://found.no/play/gist/2de967d844c5fbc14d2f
Setting explain to true is very useful when working with problems like this, as you see exactly what Lucene is doing when it's scoring.

Rails 3 - which sql query for related tags

I'm planning this feature now for a long time, and I just can't get started with it really, cause I don't know how to express it in code. Sometimes when I think I got it and know what I want, I suddenly get trapped again and everything stops making sense.
I have tags and taggings, so a has_many through relation with articles. You could call article.tags and tag.articles.
Now, each tag has their show page, basically like stackoverflow. And on this show site I want to list related tags, among others. My approach to these related tags is, that it should be those tags, which most often are tagged as well, at an article, which is tagged with the show tag. I hope this makes some sense.
Example: I'm on /tags/obama, so the related tags should be those that most often are used at articles, that include the tag obama. If I had 4 articles, and 3 of them included 'obama' and all of those 3 as well included the tag 'united_states' for example, then the most related tag to tag 'obama' would be 'united_states'. Sorry if I'm wordy..
I'm not even sure, if this is the best approach to find related tags, but this idea works fine for me. However, I can't implement it.
First I would need to fetch all articles, that include the show tag. So tag.articles. But what's the next step?
tag.articles.each do |article|
article.tags
... im just getting confused at this point.
I think the best way to solve this is to have a many to many relation between tags, so a tag can have many tags. Then in the relation between two tags, you store the count of how many instances they occur together.
You could also simply create a new tag-to-tag connection each time the tags occur in the same article. This will however create some redundancy in the database.
If you do not want to introduce another table, you can get this to work the way you started, except it might be very slow with even a fairly small amount of tags. But here is how I would have done this, if you can not make a Tag-to-tag connection:
hash_storage = Hash.new(0) #0 is the default value
tag.articles.each do |article|
if article.tags.each do |t|
#we now know that this tag "t" is in the same article as our original tag
if t!=tag #we don't care if t actually the same as our original tag
hash_storage[t]+=1
end
end
end
#Now, this is a bit messy, but we need to sort the hash.
ordered_tags = hash_storage.map{|k,v| [v,k]}.sort.reverse.map{|a,b| b} #there might be a smarter way of doing this.
ordered_tags.each do |t|
#do whatever. the tags should now be ordered by their relative frequence of occurrance together with the initial tag.
end
Hope this helps :)

What's a good way to insert a resource id into the params of another resource?

I'm really new to programming, so I'm having trouble explaining this -- please forgive.
I have a Document model and a Note model in my rails app. A note belongs to a document, and a document has many notes -- the foreign key in the notes table is document_id.
On my document show page, I have a form for a note which uses a :content attribute as a text_area field.
What I'd like to do is pass the document's id into the note params so the note would have both the :content the user submits alng with the :document_id based on the document_path.
Currently I'm adding the :document_id into the note's params hash using a hidden_field form helper, and sending the whole thing to the NotesController, but I hope there's a cleaner / perhaps easier way.
If this makes sense, can someone suggest a better way to do this? Thank you.
In your routes have something like
resources :documents do
resources :notes
end
Then you should be adding a note via this route
/documents/5/notes/new
Then in your NotesController have
def create
#document = Document.find(params[:document_id])
#note = #document.notes.build(params[:note])
if #note.save
# Blah
else
# Blah
end
end
(In no way has this been tested - but it gives you an idea of how to do it in a RESTFUL style without hidden fields)

Systematic way to upgrade from attachment_fu to carrierwave?

I'm working on upgrading an app to Rails 3, and attachment_fu is broken so I'm moving to carrierwave. Is there a systematic process that I can go through to upgrade from attachment_fu to carrierwave? Or a tutorial for it? Right now, I'm more interested in getting everything on the database end right. I'm using the filesystem store option for attachment_fu and carrierwave.
I've found a module, UploaderFu from http://ruby.simapse.com/2011/03/migrate-attachmentfu-to-carrierwave.html that tells carrierwave to use the same directories and filenames as attachment_fu. But it's not the entire answer, just part of it.
For example, in the db, I have a UserImage model, with :filename, :content_type, :size, :width, :height, and :user_id attributes. I added a :user_avatar column, and the following to my model
attr_accessible :user_avatar
mount_uploader :user_avatar, UserAvatarUploader
What exactly gets stored in :user_avatar. Is it just the filename? or something else? Do I just need to write a migration to move the data in :filename (stored like "hello_world.png") to :user_avatar? If that's the case I should just use the original :filename instead of creating a :user_avatar column, right?
The column you mount the uploader on is supposed to store an "identifier" for the uploaded file. By default it's just the filename, but you can override it to be almost anything apart from the ID of the record (because you can't know what that is until after saving).
To override: in your uploader class, add this definition :
def identifier
# This is what gets put in the database column!
model.created_on
end
In this example I've used the created_on attribute from the model. If you want to create your own storage mechanism then you need to be able to uniquely identify files by this identifier so be careful what you choose.
I would suggest renaming the column so it describes the file that's being uploaded (like in the carrierwave example). Then you can always change the identifier from filename to something else later.

Ruby on Rails 3: rails_admin + puret?

Did someone try to integrate puret into rails_admin? I can't make a language switch to edit different translations :(
Changing I18n.locale forces whole rails_admin to use specified locale.
Now I got the solution. The two can work together well. In short:
Delete the pureted column(s) in your model
If you have the column pureted still in your model, rails form helper will bypass puret. That is, if a model called Post has a field called contents to be i18ned, the table posts SHOULD NOT have the column contents.
Actually we should use globalize3 instead. With this you do not need to remove the original column. And puret doens't support nested attributes assignment. globalize3 works very well.