I'm developing an app that requires the user to enter info into a form. Its has basic validation on some of the fields to check that the're not blank.
The user model has many user_entries
has_many :user_entries, dependent: :destroy
and the user_entry model belongs to user
belongs_to :user
the problem arises with the validation in the user_entry model
validates :name, :address, :email, presence: true
before adding the foreign key user_id to the user_entries table this code worked fine, I could fill out the form with no problem and add the entries to the table. But I need to capture the current user id within the user_entries table so I can trace an entry to a user.
def create
#user_entry = UserEntry.new(params[:user_entry])
#user_entry.add_comp_connections_from_entered_competition(current_entered_competition)
#user = current_user
#user_entry = #user.user_entries.build
#--etc--#
removing the validation lets me do this, but I don't want to remove it. It seems that removing the foreign key lets me validate. But I want both to work, any help would be very much appreciated, thanks
As stated by SteveTurczyn changing
#user = current_user
#user_entry = #user.user_entries.build
to just
#user_entry.user = current_user
makes the code work, like solving so many problems its a case of not over complicating things.
thanks again Steve Turczyn
Related
Using the Simple Form gem, how can I only allow a user to submit the form only if their email has not yet been used to submit a form.
In addition to Venom's answer, I recommend using unique index.
Because there may be a situation when there will be requests with the same email at the same time. And they will be validated. In this case, you will have duplicates.
For this purpose make constraints. It will be something like
$ rails g migration AddIndexToObjects
class AddIndexToObjects < ActiveRecord::Migration
def change
add_index :objects, :email, unique: true
end
end
Use it in your model which has an email field, and not in your controller, add the following code
validates :email, uniqueness: true
what does this code do?
This will prevent users to use email id which are already present in your database. don't forget to check right if I'm correct.
Thanks.
I have a Company model and an Employer model. Employer belongs_to :company and Company has_many :employers. Within my Employer model I have the following validation:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
I'm running into a problem where the above validation fails. Here is an example setup in a controller action that will cause the validation to fail:
company = Company.new(company_params)
# company_params contains nested attributes for employers
company.employers.each do |employer|
employer.password = SecureRandom.hex
end
company.employers.first.role = 'Admin' if client.employers.count == 1
company.save!
admin = company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update(some_attr: 'some_val')
On the last line in the example code snippet, admin.update will fail because the validation is checking to see if company_id is included in the list, which it is not, since the list was generated before company was saved.
Obviously there are ways around this such as grabbing the value of company.id and then using it to define admin later, but that seems like a roundabout solution. What I'd like to know is if there is a better way to solve this problem.
Update
Apparently the possible workaround I suggested doesn't even work.
new_company = Company.find(company.id)
admin = new_company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update
# Fails validation as before
I'm not sure I understand your question completely, but there is an issue in this part of the code:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
The validation is configured on the class-level, so it won't work well with updates on that model (won't be re-evaluated on subsequent validations).
The docs state that you can use a block for inclusion in, so you could try to do that as well:
validates :company_id, inclusion: {in: ->() { Company.pluck(:id).prepend(nil) }}
Some people would recommend that you not even do this validation, but instead, have a database constraint on that column.
I believe you are misusing the inclusion validator here. If you want to validate that an associated model exists, instead of its id column having a value, you can do this in two ways. In ActivRecord, you can use a presence validator.
validates :company, presence: true
You should also use a foreign key constraint on the database level. This prevents a model from being saved if there is no corresponding record in the associated table.
add_foreign_key :employers, :companies
If it gets past ActiveRecord, the database will throw an error if there is no company record with the given company_id.
I have two tables: admin_users and users. I want all the created names to be unique (a regular user can't create a name already taken by an admin user and vice-versa). I'm having trouble writing a validates_uniqueness_of validation that is able to analyze information in a different table. I think I have to use a scope of some sort, but I tried all sorts of combinations and couldn't get it to work. To be clear: I'm looking for the correct code to replace the question marks below.
validates_uniqueness_of :user_name, :scope => #???Look in admin users
#table and check to make that this name is not taken.
Any help would be very much appreciated. Thanks!
You can create a custom validator for this.
class UserNameValidator < ActiveModel::Validator
def validate(record)
if AdminUser.exists?(user_name: record.user_name)
record.errors[:base] << "An admin user have this username!"
end
end
end
class User < ActiveRecord::Base
validates_with UserNameValidator
end
How would I validate a model in the following scenario. We have three models, being account, time log and project. An account has_many projects, and a project belongs_to account.
When a user creates a time log, they are able to select from a list of projects associated with that account, put in some more details, and save the log.
One of our developers has pointed out that it's possible to manipulate the code going back to the controller when a time log is being saved and if you pass the id of a project belonging to another account back to the controller, that project name then becomes visible in a view. In this way you could build a list of other account's projects, which is not cool.
So what I want to achieve is to validate the record being saved to ensure that the project id is actually a project associated with the current_account.
How would I achieve this?
At the moment, this is how I am building the time log
def create
#log = #employee.time_logs.build(params[:employee_time_log])
#log.account_id = current_account.id
if #log.save
flash[:notice] = "Time log sucessfully saved."
redirect_to employee_time_logs_path(#employee)
else
render :form
end
end
and the time log model looks like this
class EmployeeTimeLog < ActiveRecord::Base
#validations
validates :date, presence: true
validates :description, presence: true
#associations
belongs_to :employee
belongs_to :account
belongs_to :company_project
end
You're talking about a case of privilege escalation here.
The Rails Security Guide has some tips about this:
This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and they are not allowed to see that information, they will have access to it anyway. Instead, query the user's access rights, too:
#project = #current_user.projects.find(params[:id])
In your case, you want to allow this:
#log = #employee.time_logs.build(project_id: 'good', …)
and disallow this:
#log = #employee.time_logs.build(project_id: 'bad', …)
All projects belonging to an account are queried like so:
current_account.projects
which can be used for further queries:
current_account.projects.find('good')
#=> returns a record because ID belongs to account
current_account.projects.find('bad')
#=> raises ActiveRecord::RecordNotFound
And so that's your way of ensuring you have the right project_id passed to your controller!
user_supplied_project_id = params[:project_id]
timelog_params = params.merge(project_id: current_account.projects.find(user_supplied_project_id))
#log = #employee.time_logs.build(timelog_params)
Thanks for all the help. This was the solution in the end
user_supplied_project_id = params[:employee_time_log][:company_project_id]
timelog_params = user_supplied_project_id == '' ? params[:employee_time_log].merge(company_project_id: '') : params[:employee_time_log].merge(company_project_id: current_account.company_projects.find(user_supplied_project_id).id)
I have this model:
class User < ActiveRecord::Base
attr_accessible :subscription_process
def self.prepare_user
user = User.new
user.subscription_process = true
user.save
end
end
Inn the email that is send to the user - I use devise I have subscription_process that is equal to true. I want to know if subscription_process is saved somewhere?
Don't confuse attr_accessor and attr_accessible - those are two completely different things.
As for the question, the value is stored in the database.
user.subscription_process = true
user.save # here, it gets saved.
When you say obj.save then the it would be inserted in database and the values would be hold in that object. In your case when you save it, it will insert in Users table in database and the values are available in user object with id.
To understand attr_accessible and attr_accessor please go through this link:
Difference between attr_accessor and attr_accessible
Hope this helps !!!