Rails: Set creator of Entry - ruby-on-rails

Currently, I can add the creator_id like this in my controller:
#entry = Entry.new(params[:entry].merge(:creator => current_user._id))
If this is my model:
class Entry
include Mongoid::Document
belongs_to :User
field :creator, :type => String
field :title, :type => String
field :content, :type => String
field :scorea, :type => Integer
field :scoreb, :type => Integer
field :scorec, :type => Integer
end
Is there a better way to do this?

Your model doesn't looks very good, do you really want to store the user_id in a string field?
I suggest you change your models to following:
class Entry
include Mongoid::Document
belongs_to :creator, :class_name => 'User', :inverse_of => :entries
# field definitions
end
class User
include Mongoid::Document
has_many :entries, :inverse_of => :creator
end
Once you change the models you can continue using what you are now or alternatively:
#entry = current_user.entries.build(params[:entry])
Update:
The method to initialize entry is not much different in the way I did it. It is just more towards the rails way of doing things. The main difference is that you were not using the associations. From your model definitions it is clear that you want a one-to-many association between user and entries and this is how you create such associations. Associations has a lot of goodies attached to them, like you can do following things:
user.entries << entry # add a entry to users, will automatically change entry.creator_id
entry.creator = user # sets creato_id = user_id
entry.creator # returns associated user. no need to do User.find(entry.creator_id)
user.entries # returns all entries for use <=> Entry.where(creator_id: user.id)
for more details go to http://mongoid.org/docs/relations.html

There are no better way to do. Or you can do it in 2 line :
#entry = Entry.new(params[:entry])
#entry.creator = current_user._id
this second case allow you to add creator field in attr_protected

You can do it in this manner
#entery = Entery.new(params[:entry])
#entery.creator = current_user
or
#entery.creator_id = current_user.id
hence you can assigned id of creator to this entery.

Related

Belongs_to different field name

I've inherited quite a weird table layout:
callbacks
id, note, user
admin
id, name, password
In callbacks, the user is set to the name of the admin rather than the actual ID. Now I need to be able to call callbacks.user and have rails lookup the admin with that name and then bind it to that record.
I have a model for admin that is called users
How would I go about that?
You can override the default methods.
def user
User.find_by_name(user_name)
end
def user=(obj)
self.user_name = obj.name
end
def user_name
self[:user]
end
def user_name=(name)
self[:user] = name
end
Other option , to make it work with belongs_to, there is primary_key option but need to have a different name than the attribute user
# Callback.rb
belongs_to :user_model , :class => "User", :foreign_key => :user, :primary_key => :name
# User.rb
has_one :callback , :foreign_key => :user, :primary_key => :name

Why doesn't my polymorphic_type field get assigned automatically by rails

I'm using single table inheritance in conjunction with a polymorphic association. Here are my models.
class ChangeInformation < ActiveRecord::Base
belongs_to :eventable, :polymorphic => true
end
class Race < ActiveRecord::Base
has_many :track_condition_changes, :as => :eventable, :class_name => "ChangeInformation"
#other associations omitted
end
class TrackConditionChange < ChangeInformation
end
The change_informations table has the following fields:
type #sti field
change_code
eventalbe_id #polymorphic id
eventable_type #polymorphic type
description
When I use the following create method:
TrackConditionChange.create(:change_code => 1, :eventable_id => 3 :description => "test")
a TrackConditionChange record is created, with the type field populated, however, the eventable_type field (which should be Race) is not populated. I was under the impression that rails populated this field automatically similar to the STI type field. Was I under the wrong impression or is there a problem with my associaition setup.
Thanks for the input.
If you're only passing in the eventable_id, how will it know what type it is? You will have to either pass the entire eventable object or build it based on the track_condition_changes relationship:
1. Pass the eventable object:
race = Race.find(3)
TrackConditionChange.create(:change_code => 1, :eventable => race, :description => "test")
2. Build and save based on the relationship:
race = Race.find(3)
race.track_condition_changes << TrackConditionChange.new(:change_code => 1, :description => "test")

embeds_many and embeds_one from same model with Mongoid

I have two models, Blog and Theme. A Blog embeds_many :themes and Theme embedded_in :blog. I also have Blog embeds_one :theme (for the activated theme). This does not work. When creating a theme with blog.themes.create it's not stored. If I change the collections so they're not embedded everything works.
# This does NOT work!
class Blog
embeds_many :themes
embeds_one :theme
end
class Theme
embedded_in :blog
end
BUT
# This DOES work!
class Blog
has_many :themes
has_one :theme
end
class Theme
belongs_to :blog
end
Anyone know why this is?
UPDATE
Also there is a problem with assigning one of themes to (selected) theme.
blog.themes = [theme_1, theme_2]
blog.save!
blog.theme = blog.themes.first
blog.save!
blog.reload
blog.theme # returns nil
With this approach you'll embed the same document twice: once in the themes collection and then in the selected theme.
I'd recommend removing the second relationship and use a string attribute to store the current theme name. You can do something like:
class Blog
include Mongoid::Document
field :current_theme_name, type: String
embeds_many :themes
def current_theme
themes.find_by(name: current_theme_name)
end
end
class Theme
include Mongoid::Document
field :name, type: String
embedded_in :blog
end
Note that mongoid embeded documents are initialized at the same time that the main document and doesn't require extra queries.
OK, so I had the same problem and think I have just stumbled across the solution (I was checking out the code for the Metadata on relations).
Try this:
class Blog
embeds_many :themes, :as => :themes_collection, :class_name => "Theme"
embeds_one :theme, :as => :theme_item, :class_name => "Theme"
end
class Theme
embedded_in :themes_collection, :polymorphic => true
embedded_in :theme_item, :polymorphic => true
end
What I have discerned guessed is that:
the first param (e.g. :themes) actually becomes the method name.
:as forges the actual relationship, hence the need for them to match in both classes.
:class_name seems pretty obvious, the class used to actually serialise the data.
Hope this helps - I am obviously not an expert on the inner workings on mongoid, but this should be enough to get you running. My tests are now green and the data is serialising as expected.
Remove embeds_one :theme and instead put its getter and setter methods in Blog class:
def theme
themes.where(active: true).first
end
def theme=(thm)
theme.set(active: false)
thm.set(active: true)
end
There is no need to call blog.save! after blog.theme = blog.themes.first because set performs an atomic operation.
Also, don't forget to add field :active, type: Boolean, default: false in your Theme model.
Hope this works with you.

Filling out an inherited mongoid document using nested attributes

Given the following models:
class Company
include Mongoid::Document
has_many :workers, autosave: true
accepts_nested_attributes_for :workers
attr_accessible :workers_attributes
end
class Worker
include Mongoid::Document
field :hours
attr_accessible :hours
belongs_to :company
end
class Manager < Worker
field :order
has_many :contributors, :class_name => "Worker"
attr_accessible :order, :contributors
end
class Contributor < Worker
field :task
belongs_to :manager, :class_name => "Worker"
attr_accessible :task
end
How does one create a manager in a company in the controller and view using nested attributes?
Here's my guess:
def new
#company = Company.new
#company.workers = [Manager.new]
end
def create
#company = Company.new params[:user]
if #company.save
redirect_to root_url, :notice => "Company with manager created."
else
render :new
end
end
= semantic_form_for #company do |f|
= f.semantic_fields_for :workers do |worker_fields|
= worker_fields.inputs do
= worker_fields.input :hours
= worker_fields.input :order
problem is the order field which specifically belongs to the manager is not persisting after the create. Also when the data is improperly filled there is an error:
undefined method `order' for #<Worker:0x0000000646f018> (ActionView::Template::Error)
So is there a way for nested attributes to handle inheritance in the models from mongoid?
The question is related to Can nested attributes be used in combination with inheritance? except instead of active record using mongoid.
Honestly, this is a paraphrasing of my code... the real code is more complex situation although i believe these are all of the relevant parts. If you have more questions ask.
UPDATE:
I changed the view to the following:
= semantic_form_for #company do |f|
- #company.workers.each do |worker|
- if worker._type == "Manager"
= f.semantic_fields_for :workers, worker do |worker_fields|
= worker_fields.inputs do
= worker_fields.input :hours
= worker_fields.input :order
I do not get the error anymore, however the nested attributes do not update the company object properly. The params are the following:
{"company"=> {"workers_attributes"=>{"0"=>{"hours"=>"30", "order" => "fish", "id"=>"4e8aa6851d41c87a63000060"}}}}
Again edited for brevity. So the key part is that there is a hash between "0" => {data for manager}. The workers data seems to be held in a hash. I would expect the data to look more like the following:
params = { company => {
workers_attributes => [
{ hours => "30", "order" => "fish" }
]}}
This is different because the workers data is held in an array instead of a hash. Is there another step to get the nested attributes to save properly?
Thanks
what version of Mongoid are you using? Because I don't think the use of refereneces_many is encouraged -- Not that that's related to your problem here, just wanted to probe what version you're using. In the doc on the gorgeous Mongoid.org, get this, I had to learn it the hard way, they say for Updating your records, you need to the autossave set to true. That's NOT accurate. You need it for even creating
so:
class Company
include Mongoid::Document
has_many :workers, :autossave => true # your money shot
accepts_nested_attributes_for :workers
attr_accessible :workers_attributes
end
ADDED:
I was re-reading your code, I spotted the following that might be the problem: Your Company model is set to has_many :workers and is set to accept nested attribbutes for Worker when changes come in, correct? And there is a field named Order in your Manager model which is subclassed from Worker. Yet you're having a form whose nested fields part is pointed at Worker not at Manager, the model that actually has the Order field. And that's obviously not enough, because Company isn't having_many :managers yet, you may need to set it to has_many :managers in the Company model as well.

Dynamic fields with Thinking Sphinx

I'm building an application where I have products and categories. Category has_many properties and each property has a list of possible values. After a category is set to the product all properties show up in the form and the user can set that property to one of the properties possible values.
My question is:
Is it possible for Thinking Sphinx to filter the products through a property and property value ex:
:with => {:property_id => property_value}
If it's possible, what is the best way to implement this? If not is there any other library out there to solve this problem?
Thanks
/ Ola
One approach is to store the property_id as multi-value attribute.
class Product < ActivRecord::Base
has_one :category
has_many :properties, :through => :category
KVP = "###"
define_index do
has properties("CONCAT(`properties`.`key`, \"%s\", `properties`.`value`)" %
KVP, :as => :category_key_value
end
def search_with_properties keys, with_attr={}, p={}
wp = (with_attr||{}).dup
values = p.map{|k, v| "#{k}#{KVP}#{v}"} unless p.empty?
wp = wp.merge({:category_key_value => values}) unless values.empty?
search keys, :with => wp
end
end
class Category < ActivRecord::Base
belongs_to :product
has_many :properties
end
class Property < ActivRecord::Base
belongs_to :Category
#key E.g: region
#value E.g: South West
end
Now you can issue following search commands:
Product.search_with_properties("XYZ", nil, :region => "South West")
Try this:
Add the following to your define_index:
has properties(:id), :as => :property_ids
Then you can use :with / :without like:
:with => {:property_ids => property_value}
Does this answer your question:
https://github.com/freelancing-god/thinking-sphinx/issues/356

Resources