I am building a rails app and have create a basic and pro plan in database, here is output of Plan.all from rails console:
=> #<ActiveRecord::Relation [#<Plan id: 1, name: "basic", price: #<BigDecimal:7f9aad0bf578,'0.0',9(27)>, created_at: "2016-11-03 04:21:55", updated_at: "2016-11-03 04:21:55">, #<Plan id: 2, name: "pro", price: #<BigDecimal:7f9aad0be448,'0.1E2',9(27)>, created_at: "2016-11-03 04:22:21", updated_at: "2016-11-03 04:22:21">]>
When I create a user under either plan i get this error:
1 error prohibited this user from being saved: Plan must exist
Not sure why it is not picking up the plans.
The error "Plan must exist" when you create a user means that whatever plan_id you gave to the user does not match up with the id of an actual plan in the database. Check the plans you have created, look a their ids, and make sure the plan_id you give to your user matches the id of one of those plans.
Note: it is not enough to create database tables for each of the 2 types of plans, you must create actual instances of the plans.
Also: check to make sure you has_many / belongs_to relationship is set up correctly.
Related
I have a Rails 5.1 project using rspec/fixtures and I am having trouble getting fixtures to load objects associated with belongs_to/has_one/has_many: the object I requested the fixture for comes back with its _id columns filled with a seemingly-random number and ActiveRecord sees the association as nil. This occurs on large classes with many associations as well as small data classes with only a few fields.
If, in my test code, I assign those associations with normal Ruby code, objects behave as normal and my tests pass. However when loading the same data through fixtures, associated records are not available and tests that require data spanning across associations fail.
As an example, here are two affected classes:
#app/models/location.rb
class Location < ActiveRecord::Base
has_many :orders
has_many :end_user
belongs_to :retailer
belongs_to :depot
end
#app/models/retailer.rb
class Retailer < ActiveRecord::Base
has_many :locations
end
And here are two corresponding fixtures files:
#spec/fixtures/locations.yml
loc_paris:
retailer: ret_europe (Retailer)
name: "Paris"
nickname: "paris"
loc_washington:
retailer: ret_usa (Retailer)
name: "Washington"
nickname: "washington"
#spec/fixtures/retailers.yml
ret_europe:
name: "AcmeCo France"
nickname: "acmecofr"
currency_type: "EUR"
ret_usa:
name: "AcmeCo USA"
nickname: "acmecousa"
currency_type: "USD"
With the above data, running pp locations(:loc_paris) results in:
#<Location:0x0000000006eee1d8
id: 35456173,
name: "Paris",
nickname: "paris",
retailer_id: 399879241,
created_at: Wed, 23 May 2018 22:39:56 UTC +00:00,
updated_at: Wed, 23 May 2018 22:39:56 UTC +00:00>
Those id numbers are consistent through multiple calls, at least in the same RSpec context. (I put pp locations(:loc_paris) in a let block.) Yet pp locations(:loc_paris).retailer returns nil.
I tried using FactoryBot however we had to switch away from it. I am trying to give fixtures an honest shake but it seems like we are best off simply building data objects in the actual test code... because that solutions works without complaining :/
Am I doing something wrong here? Are we asking too much of fixtures?
Thank you!
Tom
Problem with fixtures
Looking at what you've done, locations(:loc_paris) will find the record described in locations.yml, but locations(:loc_paris).retailer won't.
Rails Associations work like this:
locations(:loc_paris).retailer will look for the retailer with retailer_id mentioned in locations(:loc_paris) record. In your case retailer_id: 399879241 and there is no reseller with this id that's why it returns Nil.
Solution:
Describe fixtures like this:
#spec/fixtures/locations.yml
loc_paris:
retailer_id: 1
name: "Paris"
nickname: "paris"
loc_washington:
retailer_id: 2
name: "Washington"
nickname: "washington"
#spec/fixtures/retailers.yml
ret_europe:
id: 1
name: "AcmeCo France"
nickname: "acmecofr"
currency_type: "EUR"
ret_usa:
id: 2
name: "AcmeCo USA"
nickname: "acmecousa"
currency_type: "USD"
Now, locations(:loc_paris).retailer will look for the retailer with retailer_id mentioned in locations(:loc_paris) record i.e. retailer_id: 1 and there is a reseller ret_europe with this id. Problem Solved
When you run rspec, at first rspec saves these fixtures into your database with some auto-generated id values (if id not provided explicitly), that's why id and reseller_id are some random values. If you don't want the id of locations.yml record to be some random value, you can provide it yourself like this:
loc_paris:
id: 1
retailer_id: 1
name: "Paris"
nickname: "paris"
Tips:
As rspec runs in test environment (mentioned in app/spec/rails_helper.rb) and as I mentioned earlier whenever you run rspec, at first it saves the fixtures into your database. If your local and test database are same, fixtures will replace the actual database records of your database. In your case, records in locations and resellers table record will be completely erased and replaced with these fixtures. So, make different database for test environment.
Hope this answer is helpful
In ruby on rails, we usually assign data in model by console.
like #model = Model.attribute (data). Like #user = User.create("John")
My question is, if I want to have the data fixed, can I do it through model or controller? SO that if I want to change the detail, I do not have to check and find in console.
For example, I need 5 users and 5 users only, so I set user_id = 1 is John user_id = 2 is David...etc in model. Can I do that? How?
You can create "fixed" data by seeding data via the seeds.rb file in your Rails application.
Let's suppose you want to create a user with specific data. Go into your app's db directory and open seeds.rb where you can add code that writes entries in your database.
User.create( email: 'patron#patron.com',
system_id: 2,
subdomain: 'foo',
external_id: '',
first_name: 'Joe',
last_name: 'Patron',
phone_number: '213 555 1212',
role: 'default',
user_status_id: 1,
password: 'password',
password_confirmation: 'password',
terms_accepted_at: datetime,
created_at: datetime,
updated_at: datetime)
You can see that you're calling the create method from whatever model you're working with and passing along all required parameters -- in other words, you're just using Ruby to build objects.
Once you have all your objects created, remember to run rake db:seed any time you reset your database in order to run the seeds.rb file to populate your database.
In my controller I have a #attach object and when I inspect it, it has values as
[#<MessageAddlAttachment id: 80, reminder_id: 112, msg_attachment_file_name: "24.png", msg_attachment_content_type: "image/png", msg_attachment_file_size: 272368, created_at: "2013-10-10 12:04:37", updated_at: "2013-10-10 12:04:37">, #<MessageAddlAttachment id: 81, reminder_id: 112, msg_attachment_file_name: "37.png", msg_attachment_content_type: "image/png", msg_attachment_file_size: 333986, created_at: "2013-10-10 12:04:37", updated_at: "2013-10-10 12:04:37">]
So now after some operation I need to create an entry in this MessageAddlAttachment table with different ids. How can I achieve it. I tried dup but it will have same ids. Please help
dup is your friend in rails 4. it will create a copy but removes the id value:
u = User.first
=> #<User id: 1, ...>
u.dup
=> #<User id: nil, ...>
u.dup.save
(0.2ms) begin transaction
...
Starting either rails 3.2 or 3.1, you want to use dup. Prior to that, you should use clone instead. That will give you new values for the id field; you might want to pay attention to what happens to your created_at and updated_at fields as well.
Another issue to watch out for is if you have any date fields with validations that say they must be after "today's date", they may have been valid when the original record was saved, but not when the new record is saved. How you resolve this will depend on your situation; you might want to disable validations completely while cloning, or adjust the values in the new records.
I'm trying to do something fairly simple. I have two models, User and Group. For simplicity's sake, let's say they look like this:
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
and
class Group < ActiveRecord::Base
has_and_belongs_to_many :users
end
Now, for some reason, I have a user that has the same group twice. In the Rails Console:
user = User.find(1000)
=> #<User id: 1000, first_name: "John", last_name: "Doe", active: true, created_at:
"2013-01-02 16:52:36", updated_at: "2013-06-17 16:21:09">
groups = user.groups
=> [#<Group id: 1, name: "student", is_active: true, created_at: "2012-12-24 15:08:59",
updated_at: "2012-12-24 15:08:59">, #<Group id: 1, name: "student", is_active: true,
created_at: "2012-12-24 15:08:59", updated_at: "2012-12-24 15:08:59">]
user.groups = groups.uniq
=> [#<Group id: 1, name: "student", is_active: true, created_at: "2012-12-24 15:08:59",
updated_at: "2012-12-24 15:08:59">]
user.save
=> true
And there is some SQL output that I've silenced. I would think that everything should be all set, but it's not. The groups aren't updated, and that user still has both. I could go into the join table and manually remove the duplicates, but that seems cludgy and gross and unnecessary. What am I doing wrong here?
I'm running Rails 3.2.11 and Ruby 1.9.3p392
Additional note: I've tried this many different ways, including using user.update_attributes, and using group_ids instead of the groups themselves, to no avail.
The reason this doesn't work is because ActiveRecord isn't handling the invalid state of duplicates in the habtm association (or any CollectionAssociation for that matter). Any ids not included in the newly assigned array are deleted - but there aren't any in this case. The relevant code:
# From lib/active_record/associations/collection_association.rb
def replace_records(new_target, original_target)
delete(target - new_target)
unless concat(new_target - target)
#target = original_target
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
"new records could not be saved."
end
target
end
The 'targets' being passed around are Arrays of assigned records. Note the call to delete(target - new_target) is equivalent in your case to delete(user.groups - user.groups.uniq) which results in an empty Array passed (since comparison is based on the id attribute of each record).
Instead, you'll need to clear out the association and then reassign the single group again:
group = user.groups.first
user.groups.clear
user.groups << group
This might be a way to cleanup those duplicates (it handles any number of groups of duplicate associations):
user = User.find(1000)
user.groups << user.groups.group_by(&:id).values.find_all {|v| v.size > 1}.each {|duplicates| duplicates.uniq_by! {|obj| obj.id}}.flatten.each {|duplicate| user.groups.delete(duplicate)}
I am able to get products from an order, but I still didn't find a way to get its option_values in order to produce it. This is how I found the product:
p = Order.find_by_number("R326153622").products.first
Then, I have its option_types through p.option_types which gives me:
=> [#<OptionType id: 935339118, name: "gender", ...>,
#<OptionType id: 935339117, name: "size", ...>,
#<OptionType id: 643188970, name: "color", ...>]
Ok! Now my headache starts. I just can't realize where to find the gender, size, and color of this product, chosen by the customer when he put it in his cart.
I'm giving up and calling the customer right away, but still wanted to understand it =D
you can do it like so
p = Order.find_by_number("R326153622").products.first
then
p.option_types.map(&:name)
what is happening here is that this form
array.map(&:method_name)
call this methods on each one of array members