DataMapper association - datamapper

I'm trying to design a schema for an email solution so that I could access the incoming and sent messages on the User object using DataMapper. The associations "inbox" and "sent" don't do what's intended. What am I doing wrong? Thanks in advance!
I've the following so far (after reading a bit and copying the friends example from DM website) --
class User
include DataMapper::Resource
property :id, Serial
property :name, String, :required=>true
property :email, String, :required=>true, :unique=>true
property :password, String, :required=>true
has n, :messages, :child_key=>[:source_id, :target_id]
has n, :inbox, 'Message', :through=>:messages, :via=>:target
has n, :sent, 'Message', :through=>:messages, :via=>:source
end
class Message
include DataMapper::Resource
property :id, Serial
property :subject, String, :required=>true
property :body, String
belongs_to :source, 'User', :key=>true
belongs_to :target, 'User', :key=>true
end

I'm answering my own question -- hope it helps someone
The following change fixes the problem I've been having --
class User
...
has n, :inbox, 'Message', :child_key=>[:target_id]
has n, :sent, 'Message', :child_key=>[:source_id]
end
Everything else, remains the same...

Related

Rails virtual attribute with ActiveRecord

I have a MySQL database table with the following simplified schema:
create_table "sensors", force: :cascade do |t|
t.integer "hex_id", limit: 8, null: false
end
where hex_id is declared as a BIGINT in MySQL. I would like for the user to type in a hexadecimal value, then convert it to base 10 and save it in hex_id. To accomplish this, I thought I would create a virtual attribute called hex to store a hexadecimal string of characters. My Sensor model looks like this:
class Sensor < ActiveRecord::Base
attr_accessor :hex
validates :hex, presence: true
before_create :hex_to_bigint
before_update :hex_to_bigint
private
def hex_to_bigint
self.hex_id = hex.to_s(10)
end
end
and the controller is using standard rails-generated code:
def new
#sensor = Sensor.new
end
# POST /sensors
def create
#sensor = Sensor.new(sensor_params)
if #sensor.save
redirect_to #sensor, notice: 'Sensor was successfully created.'
else
render :new
end
end
I created a view with a form that uses the hex attribute.
<%= f.label :hex do %>HEX ID:
<%= f.text_field :hex, required: true, pattern: '^[a-fA-F\d]+$' %>
<% end %>
When I click submit, the params array has the following contents:
{"utf8"=>"✓", "authenticity_token"=>"some_long_token", "sensor"=>{"hex"=>"E000124EB63E0001"}, "commit"=>"Create Sensor"}
My problem is that the attribute hex is always empty, and my validation fails. There are many resources on the web that explain how to use virtual attributes, but very few that explain how to use them in conjunction with ActiveRecord. I have spent hours looking for a way to solve this rather simple problem but have found nothing that works. Any help is appreciated. My ruby version is 2.0.0p481. Thanks!
Please add hex in permitted params. see the code below
private
# Never trust parameters from the scary internet, only allow the white list through.
def sensor_params
params.require(:sensor).permit(:hex_id, :hex)
end
I hope this will help you

Multiple models accessing same table

I am new to Datamapper and Ruby on Rails. I have an en existing model A, now I want to create another version of model A, v2_A. The difference between A and V2_A is that I have changed a few belongs_to from A to v2_A by changing :required => true to :required => false like following.
class A
include DataMapper::Resource
property :p1, ...
...
belongs_to :b, :required =>true
end
class v2_A
include DataMapper::Resource
property :p1, ...
...
belongs_to :b, :required =>false
end
So basically all column names in resulting tables will be same. Whenever I am doing rake db:autoupgrade a new table v2_A is being created which is not desired. I am asking is it possible both of the models access the same table A i.e. I don't want v2_A to create another table just because of that.
i am not sure about DataMapper::Resource
But i guess in your model you can write
self.table_name = "name_of_your_table"
In both of the model.

How to set a foreign key in rails?

I'm trying to save a object that has a foreign key attribute. I do not understand why it's not working. The foreign key is defined as not null in the database.
class Store < ActiveRecord::Base
attr_accessible :latitude, :longitude, :description
validates :store_group, :presence => true
validates :description, :presence => true, :length => {:maximum => 500}
validates :latitude, :presence => true
validates :longitude, :presence => true
belongs_to :store_group
end
class StoreGroup < ActiveRecord::Base
attr_accessible :name, :description, :image
validates :name, :presence => { :message => "Store group can not be empty" }
end
So, I'm trying to save a store:
group = StoreGroup.new(:name=>"name",:description=>"description",:image=>"image")
store = Store.new(:store_group=>group,:latitude=>1,:longitude=>1,:description=>"description")
store.save
However, MySQL raises an exception:
Mysql2::Error: Column 'store_group' cannot be null: INSERT INTO `stores` (`created_at`, `store_group`, `description`, `latitude`, `longitude`, `updated_at`) VALUES ('2013-02-17 04:09:15', NULL, 'description', 1.0, 1.0, '2013-02-17 04:09:15')
Why?
Thanks in advance :)
You are trying to create/save store_group object through store. Thus use:
accepts_nested_attributes_for :store_group
in your Store model
Read here about accepts_nested_attributes_for
First off, it may be easier in the long run if you add a has_many :stores to StoreGroup, for instance if you ever want to retrieve all of the stores that belong to a particular StoreGroup. Secondly, you should add the store via its StoreGroup, and since you already have an association there it's fairly straightforward (note the change to Store.create):
group = StoreGroup.create(name: "name", description: "description", image: "image")
group.stores << Store.create(lat: 1, long: 1, desc: "description")
This method will automatically set :store_group_id and save the new Store instance as a "child" of its StoreGroup. Note that you'll also want to change your code to account for existing StoreGroups, so that you can add stores to existing StoreGroups later. Using .first_or_create with a .where(...) clause is idiomatic for rails 3.2.x, though there are dynamic finders with create powers in previous versions of Rails (find_or_create_by_name_and_store_group_id, as an example).
Lastly, remove validates :store_group because association validations don't work that way. If you really must, use validates :store_group_id.

DataMapper can't save to mysql and create object with id = nil

I am following the tinyclone example in Cloning Internet Application with Ruby and is trying to create an object to be stored into mysql.
However, whenever I try to create a Url object (see code below), the result is always
"=> Url #id=nil #original="http://www.gmail.com" #link_identifier=nil"
The id is not created nor the data is stored in the database. The link to the sql database is correct as I already tried dropping the database and recreating it using DataMapper.auto_migrate!
Can anyone help? Thanks.
DataMapper.setup(:default,'mysql://root#localhost/tinyclone')
class Url
include DataMapper::Resource
property :id, Serial
property :original, String, :length => 255
belongs_to :link
end
class Link
include DataMapper::Resource
property :identifier, String, :key => true
property :created_at, DateTime
has 1, :url
has n, :visits
end
DataMapper.finalize
url = Url.create(:original => 'http://www.gmail.com')
=> #<Url #id=nil #original="http://www.gmail.com" #link_identifier=nil>
In your Url model Link is a required association. You can't create a url without a link because validation will fail. If you want to be able to create urls without associating them with a link you can write belongs_to :link, :required => false

Datamapper Many-To-Many relation

Article has many authors, editors, translaters, etc. All of class Person.
Is it possible to generate join model? Or, in this case, solution is to create each join models manually.
class Article
include DataMapper::Resource
property :id, Serial
property :published_date, Date
property :status, Enum[ :pending, :accepted, :declined, :modified, :new ], :default => :new
property :visible, Boolean, :default => false
timestamps :at
has n, :authors, 'Person', :through => Resource
end
class Person
include DataMapper::Resource
property :id, Serial
property :name, String
property :about, Text
property :gender, Enum[ :male, :female ]
property :birthday, Date
timestamps :at
has n, :articles, :through => Resource
end
looks like it impossible. Only manual model creation.