I want to validate roll_no field in students model based on student_section model field section,
student_section.rb
class StudentSection < ActiveRecord::Base
validates :standard_id, :presence=> {:message=>" cannot be blank"}
validates :section_id, :presence=> {:message=>" cannot be blank"}
validates :student_id, :presence=> {:message=>" cannot be blank"}
end
I add validation in student.rb as
class Student < ActiveRecord::Base
validates :student_id, :presence=> true
validates :student_name, :presence=> true
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates :phone, :length=>{:in => 8..15}
validates :admission_no, :uniqueness=> { scope: :org_id}
validates :roll_no, :uniqueness=> { scope: #student_section.section_id}
end
but it throws unknown field section_id
First, you should make a relationship between Student and StudentSection. If I understand you correctly, you may create a one-to-many relation.
After that your validation should work fine.
However, if you will search for more complex validation logic - you may use validates_with statement (validates_with at apidock.com)
Related
i have a Book model looking like this:
class Book < ActiveRecord::Base
belongs_to :author, class_name: 'User', touch: true
belongs_to :translator, class_name: 'User'
end
How can i search for books with specific author name? i join the tables first:
Book.joins(:author).joins(:translator)
But i cant chain
.where('authors.name = "Tolkien"')
because there is no "authors" table in the database. is
.where('users.name = "Tolkien"')
a safe approach here? is there no risk concerning both translators and authors being users in fact?
(select() method is not an option, i need activerecord::relation here)
You need to pass table name in query
Book.joins(:author).where(users: {name: 'Tolkien'})
is .where('users.name = "Tolkien"') a safe approach here?
If you are concerned about two associations using same table you might need to add a field to distinguish them
For ex. a boolean field author and use condition with association which will solve the problem
class Book < ActiveRecord::Base
belongs_to :author, -> { where(author: true) }, class_name: 'User', touch: true
belongs_to :translator, -> { where(author: false) }, class_name: 'User'
end
I've been learning Rails for about two months now. I'm creating an application for teachers to track the progress of their students. I've got the "Assignments" model working for teachers to add new assignments to a classroom, and I've got the "Users" model working so that teachers and students are both Users who can log in to the app. There's also a "Classroom" model, and each classroom has_many students and has_many assignments.
One of the main views needs to feature a spreadsheet form like traditional teacher gradebook programs. The spreadsheet will use students as the rows and assignments as the columns. Each cell in the spreadsheet will represent the student's score on that assignment.
From what I've learned so far, I think that my next step should be to create a join table that links students and assignments, with a third column for "score".
The part where I'm stumped is in creating the form so that the input cells are tied to the "score" column in the join table, so that entering a new number will change the student's score for that assignment.
I'm sure that articles or tutorials must exist somewhere for this concept, but I haven't been able to find any yet. At least, none that I recognize as a solution to this goal.
Thank you in advance for any guidance.
UPDATED TO INCLUDE CODE FOR MODELS
User Model:
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
has_many :seminars, dependent: :destroy
# Neccessary for finding all classes that a student is enrolled in
has_many :aulas, dependent: :destroy,
foreign_key: :student_id
validates :first_name, length: {maximum: 25},
presence: true
validates :last_name, length: {maximum: 25},
presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: {minimum: 6}, allow_nil: true
### Several methods that I omitted to keep the question shorter
end
Seminar Model:
(A "Seminar" is a class period, but I wanted to avoid the word, "Class" because I thought that would cause errors.)
class Seminar < ApplicationRecord
belongs_to :teacher, class_name: "User",
foreign_key: "user_id"
has_many :aulas, dependent: :destroy
has_many :students, through: :aulas, source: :student
has_many :assignments
validates :user_id, presence: true
validates :name, presence: true, length: { maximum: 40 }
end
Aula Model:
(Aula is Spanish for class. Again, I wanted to avoid the word, "Class". This model creates a relationship between a student user and a seminar (class period)."
class Aula < ApplicationRecord
# Aula is the relationship between a student and a classperiod.
belongs_to :student, class_name: "User"
belongs_to :seminar
validates :student_id, presence: true
validates :seminar_id, presence: true
end
Assignment model:
class Assignment < ApplicationRecord
belongs_to :seminar
validates :name, presence: true, length: { maximum: 40 }
validates :seminar_id, presence: true
validates :possible, presence: true
end
I would suggest you to show the Users x Assignments in a table and use in place edit, so the user can click in the cell and edit it value right there. For rails, you have a gem called "best in place" (https://github.com/bernat/best_in_place) that does the trick (there's also a rails cast that shows hot to use it: http://railscasts.com/episodes/302-in-place-editing?view=asciicast). Hope it helps, thanks
EDIT:
Answering your question, I used best_in_place for a project manager and it performance it's really nice. Looks like you're editing on microsoft excel, or something else.
About the backend: Well, you have a n x n relationship between student and assignments. You'll need a assignments_student model, for example, that belongs both to your user and assignment model and also has the score (take a look on nxn relationships if you're in doubt). So each row on your assignments_student junction table (that has two foreign keys to user and assignment table plus the score attribute) will be a cell on your table, in a way that you are editing the value of score attribute for that respective user/assignment.
Hope I made it clear. Good luck!
You might be interested in cocoon, it is a gem that allows you to do:
Dynamic nested forms using jQuery made easy
That allows you to add the "rows" to your spreadsheet-like form dynamically, based on the number of students.
Also read about Rails's accepts_nested_attributes_for, this is the foundation for allowing to do nested forms.
I have 2 models, say, User and UserProfile. User has one UserProfile. The UserProfile has a json column named 'details' with 'age' as one of the keys. I need a filter in the User index page with filtering and sorting available for 'age'. I am using ActiveRecord.
User
has_one :user_profile
#id: integer
#email: string
UserProfile
belongs_to :user
#user_id: integer
#details: json
ActiveAdmin.register User do
filter :id, as: :numeric
filter :email, as: :string
filter :age, as: :numeric
...
end
Thanks.
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.
I have a User that can have many Restaurants. I can also have multiple users.
I'd like to have it so that if User A creates Restaurant A, he should NOT be able to make another restaurant with the same name.
However, if User B goes to create Restaurant A, that should be allowed but still cannot make another Restaurant A afterwards.
I have the following has_many through relationship:
restaurant.rb
has_many :ownerships
has_many :users, :through => :ownerships
# This following ensures uniqueness of the name within the
# Restaurants table regardless of who the User is that created it.
validates :name, presence: true, uniqueness: true
user.rb
has_many :ownerships
has_many :restaurants, :through => :ownerships
ownership.rb
belongs_to :restaurant
belongs_to :user
What I've Tried
1. Adding :uniqu => true
I've tried adding :uniq => true to the restaurant.rb file so it looks like this:
has_many :ownerships
has_many :users, :through => :ownerships, :uniq => true
And removing uniqueness: true from the validation so it looks like this:
validates :name, presence: true
But that doesn't do anything useful.
2. Adding validation within ownership.rb
I've tried adding the validation to the ownership.rb file as such:
validates :restaurant, uniqueness: {:scope => :user}
But I get:
NoMethodError in RestaurantsController#create
undefined method `text?' for nil:NilClass
And I can't seem to tell it to look for the restaurant name within the scope of user either within this validation.
3. Creating before_create callback function
In my restaurant.rb file, I declared the following:
before_create :check_uniqueness
def check_uniqueness?
user = User.find_by_id(self.user_ids)
isUnique = false
user.restaurants.each do |restaurant|
if !Restaurant.find_by_name(self.name).nil? # Restaurant w/ same now found
isUnique = false
else
isUnique = true
end
return isUnique
end
end
My assumption is that before the restaurant record is created, it'll do this check_uniqueness check and if the function returns false, it'll not save.
But I'm getting the following error when I hit the submit button:
NameError in RestaurantsController#create
undefined local variable or method `check_uniqueness' for #<Restaurant:0x007f95a16d10f8>
Working Solution
Thanks to Robert Chuchro's help below, I was able to get the validation to work. Here's what I did:
restaurant.rb
before_create :unique_per_user?
def unique_per_user?
user = User.find_by_id(self.user_ids)
restaurant = user.restaurants.find(:all, :conditions => ["name = ?", self.name])
if restaurant.size > 0
self.errors.add(:name, ": You've already created a restaurant with this name.")
end
return (restaurant.size <= 0)
end
You can try to define a method to do this in your restaurant model
def unique_per_user?
#get user trying to create restaurant, either by paramter or association
#check if any of the user's current restaurant names match this name (return true/false)
end
now whereever you define a new restaurant check if its unique_per_user? before deciding to save it.