Django - readonly_fields renders info put not field - django-admin

I'm trying to use readonly_fields in my admin but it renders info about the field instead of the value.
My admin.py
class UserProfileAdmin(admin.ModelAdmin):
readonly_fields = ('user',)
list_display = ('user', 'accepted_terms')
admin.site.register(UserProfile, UserProfileAdmin)
It renders
{'help_text': u'', 'field': 'user', 'name': 'user', 'label': 'user'}
instead of
Test user name
What am I doing wrong?
Best regards
Michael

Is it possible you are using an older version of the admin templates (some kind of symbolic link or something)?

Related

update_columns update a string but it's nil when fetching on rails

I'm trying to save file to a Google Storage bucket, I followed the official guide for rails.
So I've this code for updating my file
after_create :upload_document, if: :path
def upload_document
file = Document.storage_bucket.create_file \
path.tempfile,
"cover_images/#{id}/#{path.original_filename}",
content_type: path.content_type,
acl: "public"
# Update the url to my path field on my database
update_columns(path: file.public_url)
end
I can store my file on my bucket, I can retrieve the public_url and update the path field on my table but when I try to fetch the path string I have a nil. Exemple on my rails console
Document.find(14)
=> #<Document id: 14, name: "Test", path: "https://storage.googleapis.com/xxxxxxxx-xxxx.x...", created_at: "2018-10-05 07:17:59", updated_at: "2018-10-05 07:17:59">
Document.find(14).path
=> nil
Document.find(14).name
=> "Test"
So I don't understand why I can access to my path field on my SQL database after an update using the update_columns of Rails.
Thanks a lot for your help
You have some method defined on Document class (or included module) that is overriding the default attribute accessor.
To find out which, write this in console:
Document.find(14).method(:path).source_location
In any case you can access directly the attribute with
Document.find(14)['path']

Custom analyzer in Tire Elastic not working with Mongoid

I am still doing something wrong.
Could somebody pls help me?
I want to create a custom analyzer with ascii filter in Rails + Mongoid.
I have a simple model product which has field name.
class Product
include Mongoid::Document
field :name
settings analysis: {
analyser: {
ascii: {
type: 'custom',
tokenizer: 'whitespace',
filter: ['lowercase','asciifolding']
}
}
}
mapping do
indexes :name, analyzer: 'ascii'
end
end
Product.create(name:"svíčka")
Product.search(q:"svíčka").count #1
Product.search(q:"svicka").count #0 can't find - expected 1
Product.create(name:"svicka")
Product.search(q:"svíčka").count #0 can't find - expected 1
Product.search(q:"svicka").count #1
And when I check the indexes with elasticsearch-head I expected that the index is stored without accents like this "svicka", but the index looks like this "Svíčka".
What am I doing wrong?
When I check it with API it looks OK:
curl -XGET 'localhost:9200/_analyze?tokenizer=whitespace&filters=asciifolding' -d 'svíčka'
{"tokens":[{"token":"svicka","start_offset":0,"end_offset":6,"type":"word","position":1}]}
http://localhost:9200/development_imango_products/_mapping
{"development_imango_products":{"product":{"properties":{"name":{"type":"string","analyzer":"ascii"}}}}}
curl -XGET 'localhost:9200/development_imango_products/_analyze?field=name' -d 'svíčka'
{"tokens":[{"token":"svicka","start_offset":0,"end_offset":6,"type":"word","position":1}]}
You can check how you are actually indexing your document using the analyze api.
You need also to take into account that there's a difference between what you index and what you store. What you store is returned when you query, and it is exactly what you send to elasticsearch, while what you index determines what documents you get back while querying.
Using the asciifolding is a good choice for you usecase, it should return results either query ing for svíčka or svicka. I guess there's just a typo in your settings: analyser should be analyzer. Probably that analyzer is not being used as you'd expect.
UPDATE
Given your comment you didn't solve the problem yet. Can you check what your mapping looks like (localhost:9200/index_name/_mapping)? The way you're using the analyze api is not that useful since you're manually providing the text analysis chain, but that doesn't mean that chain is applied as you'd expect to your field. Better if you provide the name of the field like this:
curl -XGET 'localhost:9200/index_name/_analyze?field=field_name' -d 'svíčka'
That way the analyze api will rely on the actual mapping for that field.
UPDATE 2
After you made sure that the mapping is correctly submitted and everything looks fine, I noticed you're not specifying the field that you want to to query. If you don't specify it you're querying the _all special field, which contains by default all the field that you're indexing, and uses by default the StandardAnalyzer. You should use the following query: name:svíčka.
elasticsearch needs settings and mapping in a single api call. I am not sure if its mentioned in tire docs, but I faced a similar problem, using both settings and mapping when setting up tire. Following should work:
class Product
include Mongoid::Document
# include tire stuff
field :name
settings(self.tire_settings) do
mapping do
indexes :name, analyzer: 'ascii'
end
end
# this method is just created for readablity,
# settings hash can also be passed directly
def self.tire_settings
{
analysis: {
analyzer: {
ascii: {
type: 'custom',
tokenizer: 'whitespace',
filter: ['lowercase','asciifolding']
}
}
}
}
end
end
Your notation for settings/mappings is incorrect, as #rubish suggests, check documentation in https://github.com/karmi/tire/blob/master/lib/tire/model/indexing.rb (no question the docs should be better)
Always, always, always check the mapping of the index to see if your desired mapping has been applied.
Use the Explain API, as #javanna suggests, to check how your analyzing chain works quickly, without having to store documents, check results, etc.
Please note that It is very important to add two lines in a model to make it searchable through Tire. Your model should look like
class Model
include Mongoid::Document
include Mongoid::Timestamps
include Tire::Model::Search
include Tire::Model::Callbacks
field :filed_name, type: String
index_name "#{Tire::Model::Search.index_prefix}model_name"
settings :analysis => {
:analyzer => {
"project_lowercase_analyzer" => {
"tokenizer" => "keyword",
"filter" => ["lowercase"],
"type" => "custom"
}
},
} do
mapping do
indexes :field_name, :boost => 10, :type => 'String', :analyzer => 'standard', :filter => ['standard', 'lowercase','keyword']
end
end
def self.search( params = {} )
query = params[:search-text_field_name_from_form]
Model.tire.search(load: true, page: params[:page], per_page: 5) do
query { string query, default_operator: "AND" } if query.present?
end
end
You can change the index_name(should be unique) and the analyzer
And Your controller would be like
def method_name
#results = Model.search( params ).results
end
You can use #results in your view. Hope this may help you.

How to create a multi level document using MongoId

I am developing a Ruby on Rails (3.2.6) application and is using MongoId (3.0.0) to interact with the MongoDB database. I am just wondering how do save embeded JSON objects that contains multiple levels and not just one level.
I got an old MongoDB database with this and simular structure so I need to save new documents using the same structure.
This is from the documentation and is used to add a one level document:
Person.create(
first_name: "Heinrich",
last_name: "Heine"
)
How can I add an object with this structure:
{
"basic": {
"file_id": {
"file": "cf1952761a806c56c9bee60665418f02c"
},
"share": false,
"status": "created"
},
"data": {
"id": "4fd942dder5f5e88837300026e",
"name": "roberta",
"comment": "This is a comment"
}
}
The easiest way to do this is to create classes for basic and data and embed them in your top level document.
Embedded document classes are defined in Mongoid the same way as other documents with an embedded_in call and a matching embeds_one or embeds_many in the top level document.
The other option is to simply define a Hash field, but this obviously may have any structure.
Class Person
include Mongoid::Document
field :data, :type => Hash
...
end
:data will accept any hash, even with nested hashes.

How to properly add default entries to database in Ruby on Rails?

Mostly my entries in seeds.rb are simple, like this:
User.create!(
name: "Peter"
admin: false;
# etc.
)
If I get the "Can't mass-assign protected attributes" error, I make a small change in the model, in this case user.rb:
attr_accessible: name, admin
So far so good. But how am I supposed to seed entries into tables generated by a rails gem which adds another engine to my app? Forem, for example. And I'm sure there are others.
I have added these entries to my seeds.rb file:
Forem::Category.create!(
name: "cat1"
)
Forem::Forum.create!(
title: "forum1",
description: "forum1 description",
category_id: 1
)
Forem::Topic.create!(
forum_id: 1,
user_id: 1,
subject: 'topic1',
locked: false,
pinned: false,
hidden: false,
)
Category and Forum are generated, Topic is not:
Can't mass-assign protected attributes: forum_id, user_id, locked, pinned, hidden
If I had a topic.rb model, I would know what to do. But I don't have it. Forem is an engine and I don't know of a way to make some attributes of model topic.rb visible.
I know that this line in application.rb:
config.active_record.whitelist_attributes = true
enables the protection against mass assignment. Disabling it leaves a huge security hole, so it's not an option. And disabling it didn't allow me to seed into topics table anyway.
I've also tried to use fixtures. I added this to my seeds.rb file:
require 'active_record/fixtures'
Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "topics.yml")
test/topics.yml:
one:
id: 1
forum_id: 1
user_id: 1
subject: "topic1"
created_at: 2012-05-19 19:54:19
updated_at: 2012-05-19 19:54:20
locked: false
pinned: false
hidden: false
last_post_at: 2012-05-19 19:54:21
state: "open"
views_count: 3
Error I get is - uninitialized constant Fixtures
What's wrong with my seeds.rb and fixture? Or should I use a migration?
Disabling it leaves a huge security hole, so it's not an option`
Nope, it's not a huge security hole. This is a controversial debate, but attr_accessible (and variants) are (in my and a lot of others opinion) not a good solution to the problem that is preventing users to create/update objects/attributes they should not. Put another way, attr_accessible is a model solution to a controller issue. Because that is the job of the controller to make sure that the data is cleaned and usable, to check wether the current user is allowed to do such things, etc.
So what I'd do would be to remove all references to attr_accessible and set whitelist_attributes to false.
Then it's up to you to filter your params in your controllers. You could do as done in this gist or use rails/strong_parameters, or any other way that might please you.
After that you would no longer have these issues while seeding
Seeds.rb is just ruby code. You don't have to create the whole resource in one line. Try something like this
topic = Forem::Topic.create(
:subject => "topic 1",
:locked => false
# etc
)
topic.user_id = 1
topic.save

Getting couchrest and couch_potato to recognize existing couchdb documents

I'm trying to create a basic Rails CRUD app against a CouchDB database hosted on Cloudant.
I'm using couch_potato as my persistence layer and have it connecting properly to my Cloudant database.
The issues I'm having is my first model won't see the existing documents in my CouchDB database, unless I add a ruby_class field that equals the name of my model.
My simple User model:
class User
include CouchPotato::Persistence
property :id, :type => Fixnum
property :FullName, :type => String
view :all, :key => :FullName
end
Sample CouchDB document:
{
"_id": 123456,
"_rev": "4-b96f36763934ce7c469abbc6fa05aaf3",
"ORGID": 400638,
"MyOrgToken": "19fc342d50f9d8df1ecd5e5404f5e5f7",
"FullName": "Jane Doe",
"Phone": "555-555-5555",
"MemberNumber": 123456,
"Email": "jane#example.com",
"LoginPWHash": "14a3ccc0e6a50135ef391608e786f4e8"
}
Now, when I use my all view from the rails console, I don't get any results back:
1.9.2-p290 :002 > CouchPotato.database.view User.all
=> []
If I add the field and value "ruby_class: User" to the above CouchDB document, then I get results back in the console:
1.9.2-p290 :003 > CouchPotato.database.view User.all
=> [#<User _id: "123456", _rev: "4-b96f36763934ce7c469abbc6fa05aaf3", created_at: nil,
updated_at: nil, id: "123456", FullName: "Jane Doe">]
I'm working with a large set of customer data, and I don't want to write any scripts to add the ruby_class field to every document (and I may not be permitted to).
How can I get my app to recognize these existing CouchDB documents without adding the ruby_class field?
I couldn't find much documentation for couch_potato and couchrest that shows how to work with existing CouchDB databases. Most of the examples assume you're starting your project and database(s) from scratch.
Thanks,
/floatnspace
when you are looking at the all view of your User you will see something like ruby_class == 'User' so unless you add this property to your documents you will need to work around what couch_potato provides. you could i.e. use couch_rest directly to retrieve your documents, but i don't think that this what you want.
if you start persisting or updating your own documents, couch_potato will add the ruby_class field anyways. so i think the simples solution would be to just add them there.
another thing you can do is create a view that emits the documents also when they DON'T have the property set. this approach will only work if you have just one kind of document in your couchdb:
if(!doc.ruby_class || doc.ruby_class == 'User') {
emit(doc);
}

Resources