issue displaying associated record in show action rails 5 - ruby-on-rails

For some reason I'm having an issue displaying an associated record on my account show page.
I have the following models:
account.rb has the association of: belongs_to :plan
plan.rb has the association of: has_many :accounts
# accounts_controller.rb
def show
#account = Account.find(params[:id])
#account.plan = Plan.find_by(params[:plan_id])
end
When I try to display the Plan name on the account page, it only displays the first plan name (even through i have multiple plans and the account has the plan_id properly set.
ie Account 1 has a plan_id of 2 but displays the info for plan 1 where as Account 2 has the plan_id of 1 and that shows the proper plan...
Not sure where I'm veering off course here any assistance would be appreciated.

ActiveRecord/FinderMethods#find_by find and returns the first record matching the conditions, but for that you need to pass the attribute which you're looking for and the value assigned, in your case you're passing just the value.
If you're planning on getting the plan for that specific account then Plan.find(id) would be enough.

Related

Ruby on Rails validation bypass and confusion

I am facing a strange thing on Ruby on Rails and I don't know what is the correct way to deal with this situation.
I have two models, Book and Page.
Book(name:string)
Page(page_number: integer, book_id: ID)
class Book < ActiveRecord::Base
has_many :pages
accepts_nested_attributes_for :pages
end
class Page < ActiveRecord::Base
belongs_to :book
validates_uniqueness_of :page_number, scope: :book_id
end
I have created a view from where I can update a book. I accept nested attributes for pages and there is a section where I can update book pages as well as add new pages (by a Javascript function that lets the user to add a new page row by clicking + button). As you can see I have a validation that requires the page number to be unique for a certain book to prevent duplication. I have also defined an unique index on the database level (using Postgres)
On my update action in Book's Controller I have:
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
flash[:notice] = 'Book successfully modified!'
end
end
The problem with my approach is that sometimes the validation about the page_number that I have defined on Pages model is bypassed and I get an error directly from PG ("PG::UniqueViolation: ERROR: duplicate key value violates unique constraint").
This scenario happens on 2 cases:
Trying to create two or more pages with the same number directly on one form submission
Updating existing page_number (ex from page_number: 4 to nr: 5) and creating one new page with number 4 on one form submission.
It seems that there is some problem of concurrency and order of processing the updates/creates.
For the point 2, we should somehow tell Rails to look over all records and see if there we are trying to do any duplication by combining updates with creates. Point 2 is a valid option and there should be no validation error thrown but because Rails is doing creation first it laments that a page with page_number 4 already exists (without taking into considerance that page_number 4 is being updated to 5)
I would be thankful I you could advice me how to handle this situation and be able to predict all use cases so that I do not hit the database in case of a validation error.
If this is impossible, is there a way that I can catch the error from Postgres, format and display it to the user?
I appreciate any advice!

Specify table for rails .where

Can't find same question. How can I specify select.where for model?
I need to select from different tables by one model and want to get something like this in controller:
params[:id] = 1248 // here is example of request params
id=params[:id] // this id goes to message SQL like table name with prefix:
Message(id).all => select * from messages_1248
How can I get something like this?
Thanks for answers!
UPD:
I have one table with users and many tables with messages (each table is for one pair of users). In users table there is 'messages' column with messages tables id's. And inside user_controller I need to run a query like in my question. Maybe anybody can share an example?
how about little bit change the design, with just 2 tables (user and message) just idea with details below
user table (id,name)
messages table(user_id,message_text)
you setup the relation user has_many messages (please see this link for more guide http://guides.rubyonrails.org/association_basics.html#the-has-many-association
user.rb
has_many :memberships
message.rb
belongs_to :user
for example you need to access user with specific id and the messages for this user
inside users_controller.rb
def show
#user = User.find(params[:id])
# this find user
#messages = #user.messages
# get all the messages for specific users
end

Associate a Readable User Dropdown in ActiveAdmin

I guess not much help here. When you are trying to associate a user from a dropdown list, and imagine if you have 1000000 users, you would see the user instance. I need it to show the actual user's email address.
app/models/user.rb:
has_one :company
app/models/company.rb:
belongs_to :user
The link I was given has nothing to do with the dropdown's value.
Have I setup my rails association incorrectly? Funny thing was, using rails admin I had no issue in this department as I could associate a company when creating a user but not so with active admin.
All I want is when I select the User dropdown, as in picture, I'd see a list of user email addresses.
Tim was correct all this time. I needed to create a function in the User model.
app/models/user.rb:
def display_name
email
end

Rails has_one relationship safe resource.build_resource in controller

I have a page that takes a user through a short sign up tutorial when they create their account in order to create their first resource. In my app, :hotel belongs to :user, and :user has_one hotel. For the tutorial page, in my controller, I have:
#hotel = current_user.build_hotel
Which works, except that it a user somehow finds him back on the tutorial page that command disassociates their previously created hotel. In other words, the second time the user accesses the page with:
#hotel = current_user.build_hotel
The user_id field in the hotel they created the first time becomes nil. Obviously that is a serious problem. I can do a before_filter on that page, but I'm not very happy about having a way for the user to screw everything up simply by visiting a page. How should I properly use the build command for a has_one relationship?
You can test for the existence of a hotel before building it:
#hotel = current_user.hotel || current_user.build_hotel

Validate max amount af associated objects

I have an Account model and a User model:
class Account < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :account
end
Users belong to an account and an account have a user maximum (different for each account). But how do I validate that this maximum have not been reached when adding new users to an account?
First I tried to add a validation on the user:
class User < ActiveRecord::Base
belongs_to :account
validate :validate_max_users_have_not_been_reached
def validate_max_users_have_not_been_reached
return unless account_id_changed? # nothing to validate
errors.add_to_base("can not be added to this account since its user maximum have been reached") unless account.users.count < account.maximum_amount_of_users
end
end
But this only works if I'm adding one user at a time.
If I add multiple users via #account.update_attributes(:users_attributes => ...) it just goes directly through even if there is only room for one more user.
Update:
Just to clarify: The current validation method validates that account.users.count is less than account.maximum_amount_of_users. So say for instance that account.users.count is 9 and account.maximum_amount_of_users is 10, then the validation will pass because 9 < 10.
The problem is that the count returned from account.users.count will not increase until all the users have been written to the database. This means adding multiple users at the same time will pass validations since the user count will be the same until after they are all validated.
So as askegg points out, should I add validation to the Account model as well? And how should that be done?
If you call account.users.size instead of account.users.count it will also include users which have been built but not saved to the database.
HOWEVER this will not fully solve your problem. When you call account in a user it is not returning the same account instance that #account is pointing to so it does not know about the new users. I believe this will be "fixed" in Rails 3, but in the meantime I can think of a couple solutions.
If you are saving the account the same time you are adding users (which I assume so since you are calling update_attributes) then the validation can go in there.
# in account.rb
def validate_max_users_have_not_been_reached
errors.add_to_base("You cannot have more than #{maximum_amount_of_users} users on this account.") unless users.size < maximum_amount_of_users
end
I'm not sure how you are saving the associated models, but if account validation fails they should not be saved.
The other solution is to reset the user.account instance to self when updating user attributes. You could do this in the users_attributes setter method.
# in account.rb
def users_attributes=(attributes)
#...
user.account = self
#...
end
This way user's account will point to the same account instance so account.users.size should return the amount. In this case you would keep the validations in the user model.
It's a tricky problem but hopefully this gave you some ideas on how to solve it.
The reason it is passing is because update_attributes does not go through validations.
Also - your logic only checks for the existing number of account against their maximum permitted. There is no calculation considering the number of users attempting to be added. I would think this logic belongs more in the Account model (?).

Resources