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.
Related
Hello, i'm new to rails. I have been fed up with active record associations. I did study associations from the rails guides. Yet i cant find myself a clear way to add associations to the models suggested in the diagram.
I have one doubt whether a single foreign key(SECOND MODEL) can reference two primary keys (SECOND MODEL LEVEL 2 FIRST & SECOND MODEL LEVEL 2 SECOND). This has been done because the user has to choose whether to add from the SECOND MODEL LEVEL 2 FIRST TABLE or the SECOND MODEL LEVEL 2 SECOND TABLE while inserting values into the SECOND MODEL.
If u find this hard to understand please leave a comment, ill make appropriate changes. And i would appreciate on how to query from the FINAL LEVEL FIRST with BASE-MODEL thorough a join condition.
You can use polymorphic association to refer to one table OR another, check the model below as per the posted image:
class BaseModel
has_many :first_models
has_many :second_models
end
class FirstModel
belgons_to :base_model
has_one :level_two_first_model
end
class LevelTwoFirstModel
belgons_to :first_model
end
class SecondModel
belgons_to :base_model
has_many :final_first_levels, as: :referenceable, :dependent => :destroy
has_many :final_second_levels, as: :referenceable, :dependent => :destroy
end
class LevelOneSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class LevelTwoSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class FinalFirstLevel
belongs_to :LevelOneSecondModel
end
class FinalSecondLevel
belongs_to :LevelTwoSecondModel
end
referenceable is used as the glue between the parent table and other polymorphic associations (LevelOneSecondModel OR LevelTwoSecondModel)
NB:
Don't forget to add the below line in the migration files of the 2 children tables used in polymorphic association.
t.references :referenceable, polymorphic: true, index: true
Reference:
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
I'm trying to create a form using form_for which will add Employees. For an employee i want to assign multiple specializations such as c#, asp, etc as the values dynamically. I'm using the following code in the form
<%= f.select :specilization, Specialization.all.collect{|p| [p.name, p.id]}, {}, :multiple => true %>
I've also made HABTM between employees and specialization like
Employee.rb
class Employee < ActiveRecord::Base
has_and_belongs_to_many :specializations
end
Specialization.rb
class Specialization < ActiveRecord::Base
has_and_belongs_to_many :employees
end
with these done, im not able to save the selected values in db(MySQl). Would appreciate if anyone could solve my problem or guide me on how to get this right?
Thanks in advance.
I usually solve this by using has_many :through and then in my form the select is a field_for on the join model. Like this:
class Employee < ActiveRecord::Base
has_many :employees_specializations
has_many :specializations, through: :employees_specializations
# we will be creating these join models on the employee form
accepts_nested_attributes_for :employees_specializations
end
class Specialization < ActiveRecord::Base
has_many :employees_specializations
has_many :employees, through: :employees_specializations
end
class EmployeesSpecialization < ActiveRecord::Base
belongs_to :employee
belongs_to :specializations
end
Now it's important to note that with this simplified approach I'm assuming Specializations already exist in the database and we're just selecting them and joining them to the employee we're creating/editing:
# in your controller make sure to build at least 1 new instance, the fields_for needs this
#employee.employees_specializations.build
# remember to add to your strong parameters the new join attributes
params.require(:employee).permit(
# ... other attributes ...
employees_specializations_attributes: [:id, :specialization_id]
)
You need to declare :id, :specialization_id as sub fields since employees_specializations_attributes will be a nested hash with those keys inside.
# now in your form use fields_for
<%= f.fields_for :employees_specializations do |ef| %>
<%= ef.select :specialization_id, Specialization.all.map{|p| [p.name, p.id]}, {}, multiple: true %>
<% end %>
That f.fields_for :employees_specializations will create form fields named employee[employees_specializations_attributes][][specialization_id]. Which basically says we are creating a nested association employees_specializations and setting that nested association's specialization_id (remember employees_specialization belongs_to :specialization) to the selected specialization. Note the [] in the middle of the field name, this means its an array of nested employees_specializations.
Post that and barring any validation errors you should be able to create/edit an employee and set it's specializations by selecting from a list of existing specializations and creating a join model between them.
Further reading:
http://apidock.com/rails/v4.0.2/ActionView/Helpers/FormHelper/fields_for
http://apidock.com/rails/v4.0.2/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for
http://laptite.github.io/blog/2014/02/26/deep-nesting-with-has-many-through-and-a-join-model/
Rails nested form with has_many :through, how to edit attributes of join model?
i got 2 tables connected with each other.
device and push information are my models.
class Device < ActiveRecord::Base
has_one :pushinformation
end
class Pushinformation < ActiveRecord::Base
belongs_to :device
end
these are my 2 model files and their relationships.
and these are my migration files
class CreateDevices < ActiveRecord::Migration
def change
create_table :devices do |t|
#t.integer :id
t.string "token"
t.string "carrier"
t.string "segment"
#t.datetime :created_at
#t.datetime :updated_at
t.timestamps
end
end
end
class CreatePushinformations < ActiveRecord::Migration
def change
create_table :pushinformations do |t|
t.integer "device_id"
#t.string "token"
t.string "first_name"
t.string "last_name"
t.string "nickname"
t.timestamps
end
end
end
now the thing is , i was able to create a relationship successfully in rails console by saying
device.pushinformation=push
and they were associated.
How can i make this process automated, like when i add one device- it will have a push information table filled aswell,
i thought about having the same attribute and relating them might be the solution. In this case its token and its completely unique.
How can i create this relationships? I need to be able to know which device has what kind of first_name
i m a beginner in ruby and this is a newbie question sorry guys :)
I am not sure I understand completely what you ask but my guess is that you could use a callback on create
class Pushinformation < ActiveRecord::Base
belongs_to :device
after_create :create_push_notification
private
def create_push_notification
...
end
end
check the docs
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
xlembouras's answer is right (to a degree), but as you're new, let me explain it for you:
--
Associations
ActiveRecord associations are nothing magical, they're just a way to associate two "objects" using a relational database setup.
ActiveRecord is an ORM -- "object relationship mapper" -- which basically means it just provides a level of abstraction for your ActiveRecord objects to associate with each other
Herein lies the crux of the matter - you need to apprciate how and why your associations will work, and more importantly, how to populate them correctly:
--
Models
Firstly, you need to appreciate the object-orientated nature of Ruby (& by virtue of running on Ruby, Rails). This is where the Models of Rails play such a vital role -- they allow you to build & manage objects from your database
The ActiveRecord associations give you the ability to manage the associations those objects have - maning if you build one, you should be able to build the other:
#app/models/device.rb
Class Device < ActiveRecord::Base
has_one :push_information
before_create :build_push_information #-> creates associative object before creation
end
#app/models/push_information.rb
Class PushInformation < ActiveRecord::Base
belongs_to :device
end
You need to consider the importance of what I've written above.
What you need is to create a push_information object with the same foreign_key as the device object, which can be achieved by using the build method
This will essentially create a "blank" version of your associative object, saving it with the correct foreign key etc
--
Nesting
Further to this, you have to appreciate the idea of "nesting", especially the method accepts_nested_attributes_for
This allows you to create associative / dependent objects based on your "parent" object:
#app/models/device.rb
Class Device < ActiveRecord::Base
has_one :push_information
accepts_nested_attributes_for :push_information
end
#app/models/push_informtion.rb
Class PushInformation < ActiveRecord::Base
belongs_to :device
end
This gives you the ability to do the following:
#app/controllers/devices_controller.rb
Class DevicesController < ApplicationController
def new
#device = Device.new
#device.build_push_information
end
def create
#device = Device.new(device_params)
#device.save
end
private
def device_params
params.require(:device).permit(:your, :device, :params, push_information_attributes: [:push, :information, :attributes])
end
end
This gives you the ability to populate the devices#new form like so:
#app/views/devices/new.html.erb
<%= form_for #device do |f| %>
<%= f.text_field :your_device_attributes %>
<%= f.fields_for :push_information do |p| %>
<%= p.text_field :your_field %>
<% end %>
<%= f.submit %>
<% end %>
Add a create
method to your Devise class. Something like:
def self.create(token, carrier, segment)
device = Device.new(:token => token, :carrier => carrier, :segment => segment)
pi = Pushinformation.create(device.id,..) # other params
end
I have the following which deletes a bin and everything related to it. It's great and functions;
MODEL BIN
class Bin < ActiveRecord::Base
has_many :savedtweets, :dependent => :destroy
before_destroy :mod_newtweets
def mod_newtweets
Newtweet.where(:tweet_id => #bin.savedtweets.pluck(:tweet_id)).update_all(:status => 'new')
end
end
However, it destroys a bin, deletes everything but doesn't run :mod_newtweets to update my other table and its column.
If I put this in the controller it works fine;
Newtweet.where(:tweet_id => #bin.savedtweets.pluck(:tweet_id)).update_all(:status => 'new')
I thought I've got everything done right.
Replace your method with:
def mod_newtweets
Newtweet.where(:tweet_id => savedtweets.pluck(:tweet_id)).update_all(:status => 'new')
end
You are using #bin.savedtweets in your model while you have not defined #bin anywhere. as it is an instance method you can use either self.savedtweets or only savedtweets to call the savedtweets method on current instance of Bin model.
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.