Ruby on Rails - rails g scaffold foreign key - mysql

Im new to ruby and I want ot create database with table User, Role and user Role. And my question is should I use scaffold or something else? And how to add autoincrement id in this tables? And how to add foreign key?
rails g scaffold User name:string surname:string && rails generate scaffold Role name:string id:integer

Should I use scaffold or something else?
You can use a scaffold, if what you need is all the files and changes in your project related to that specific table/model. A scaffold will add assets, models, controllers, and even tests. If you feel you don't need it, you can create a single migration which can handle the table creation in your database and that's all. If in the other hand, you need more than that, you can create a model (rails g model ...), and so on, and so forth.
And how to add autoincrement id in this tables?
By convention, Rails will add an id column in your table, unless specified otherwise. Depending on your database, it'll will use the AUTO INCREMENT clause, or a SERIAL if using Postgres. As it supports multiple relational database management systems, there are a lot of options for that.
And how to add foreign key?
When creating a scaffold, or a model, or a migration, you can use the references option. In your case If you have a User and UserRole models/tables, it'd look like this:
rails g scaffold User name && rails g scaffold UserRole user:references
You can check the Rails guides about migrations for further information.
Complement for the given question:
class ... < ActiveRecord::Migration[5.0]
def change
create_table :... do |t|
t.references :user_id_rated, references: :users, foreign_key: true
t.references :rated_by_user_id, references: :users, foreign_key: true
...
end
end
end

Related

The correct usage of a foreign key with a dependent table

I have a rails app in which a model named ClassEvents belongs to the Users model. I'd like to flag Users with is_approved and use some logic in my view to decide whether a ClassEvent should be shown.
Ideally, I don't have to look into the Users table each time I need to figure out if the ClassEvent's parent User has the is_approved flag set.
My plan is to create the is_approved row in the User table and a separate is_approved row in the ClassEvent table. This feels redundant and an opportunity for nasty bugs.
Is this a case for a foreign key in ClassEvent?
What's the correct Rails way for this situation?
If ClassEvents already belongs to the Users model, then you already have a foreign key association, something like this:
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
In that case you can get only the events from approved users like this:
ClassEvent.joins(:user).where('users.is_approved' => true) unless you're dealing w/ huge amounts of data, the performance would be fine.
You can use eager loading to load all joined data upfront.
Assuming this kind of association:
belongs_to :parent_user, :class_name => "User", :foreign_key => "user_id"
You can load the ClassEvent in the controller like so:
#class_event = ClassEvent.includes(:parent_user).find(params[:id])
Then you can check it in the ClassEvent view like so and it will not do a separate query to the User record:
<% if #class_event.parent_user.is_approved == true %>
<!--output class event data here-->
See the "Eager Loaded Associations" section on this page for more details: http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
Note too that foreign keys are not automatically set up by Rails at the database layer. I've used this nice gem to handle that in the past: https://github.com/matthuhiggins/foreigner

Rails 4.2 Ensuring uniqueness across two columns in DB as well as on instance

I am learning Rails right now as we transition a product to it. I have a problem -- and a definite lack of core skills with ruby -- that I am wondering how to address. Not only would I like an answer, I would welcome opinions on whether or not there is a better way to achieve this.
Associations:
We have a Client class which has_many :users. The User belongs_to the Client.
In addition to the :client_id column we also have a :email column that should be unique within the scope of the :client_id
Validations:
I have seen that I could do something like this to ensure that on the instance level by adding this check to the User model.
validates :email, uniqueness: {scope: :client_id}
but as far as my understanding goes, this does nothing to ensure uniqueness in the schema. Keep in mind I am trying to avoid manually altering the schema with SQL, I would like to do this with migrations if possible. In other uniqueness checks(for non scoped uniqueness), to ensure the uniqueness of something I would do something like this in the migration:
add_index :users, :email, unique: true
but that doesn't really do what I want, I don't think.
Tips, tricks, comments, suggestions, and answers welcome!
Edit:
MySQL example:
CREATE TABLE IF NOT EXISTS users (
email VARCHAR(200),
client_id INTEGER,
UNIQUE INDEX (email, client_id)
)
You can use an array as the second argument to add_index in your migration:
add_index "users", ["client_id", "email"], :unique => true
This should produce:
CREATE UNIQUE INDEX users_client_id_email ON users(client_id, email)
http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index

Rails Engine: Namespacing foreign key references to other models in the same engine

I've set up a namespaced Rails 3.2.19 engine w/ MySQL for the DB called TestAppTv with 2 models: Post and Comment.
I want Comments to belong to Posts, but I want it to refer to TestAppTv::Post specifically. I know that I can do this by specifying class_name along with my belongs_to/has_many calls.
module TestAppTv
class Comment < ActiveRecord::Base
belongs_to :post, class_name: "TestAppTv::Post"
attr_accessible :text
end
end
module TestAppTv
class Post < ActiveRecord::Base
has_many :comments, class_name: "TestAppTv::Comment"
attr_accessible :text, :title
end
end
Now, my confusion is in the database. It seems that the foreign_key by default in the test_app_tv_comments table is "post_id". However, it seems to me that this isn't following the same namespacing idea as the rest of the application. It seems like it would be ambiguous whether post_id was referring to test_app_tv_posts.id or some base posts.id table from the base application or another engine.
Is there some proper way to namespace the foreign_key that rails will use by default for all of the built-in magic?
When I've tried to use foreign_key to manually specify the key as test_app_tv_post_id, I end up running into lots of issues around "inverse", and the default magic helpers not working anymore. For example, doing TestAppTv::Comment.create(post: TestAppTv::Post.first, text: "test") doesn't work, and I have to specify the foreign_key field automatically.
Thanks for any advice or help on this topic! I appreciate it!
If anyone finds this post in the future and was confused as I was at why the foreign key wasn't namespaced the same, the answer is that it doesn't matter that it's not namespaced.
Since Ruby handles class lookups by first looking within the current module and then up the module tree to the base namespace, models that are defined within the same Rails engine are used before any models defined in the base application the engine is included in. This means that a field of "post_id" is sufficient for namespaced engines referring to a particular TestAppTv::Post since TestAppTv::Post is what is found first when a lookup for the class "Post" is made within the TestAppTv engine's module.
This wasn't mentioned anywhere as far as I know, so I think this is probably something that is just assumed to be common ruby knowledge. I hope this can help others out there.

How to create a model with multiple tables in Rails?

In my Rails application I am linking into a MySQL database from the legacy PHP application. The naming conventions are incorrect, so am making use of self.table_name to connect models to their respective tables.
I have a requirement to show information from multiple tables into one resource. All these tables have the same column structure. Can I create a model that pulls information from each of these tables? How do I do that? I have been playing around with find_by_sql but am yet to have any success
EDIT: This is all to be read only, no updating is required.
From your question I believe you are planning to load a other models from one particular model. My suggest is to use a polymorphic relationship.
class MainModel
has_many :sub_model, polymorphic: true
end
class Item1
belong_to :main_model, as: :sub_model
end
class Item2
belong_to :main_model, as: :sub_model
end
Now in the view you will have to write your data as follows.
#main_model.sub_model.name | #main_model.sub_model.value
Since all the other models/tables has the same structure you won't have to change the attribute.
And when updating it, you just accept the values of the sub_models as a nested attribute and they will update the corresponding model.
For more details on how to setup a polymorphic relationship visit Setting up a polymorphic association

Limit a user to view only associated records in rails

I have an application with three Models (Profile -> SubModel -> SubSubModel) chained together with has many relationships. I am trying to limit a user, after logging in, to only retrieving records that are associated with their Profile. I am very new to rails and this is what I had been trying in the Profile model
has_many :submodels, :conditions => {:profile_id => self.id}
but this is returning an empty data set when calling with Profile.find_by_id(1).submodels, how else could I achieve what I am trying to do. Or should I handle this in the controller or view instead, I thought it sounded well suited for the model to handle this.
you don't need any conditions on the has_many call - by default it will only return the SubModels associated with the Profile.
If you've named your classes and foreign/primary keys to Rails conventions, just use
class Profile
has_many :sub_models
end
and let Rails figure it out.
This assumes the following:
Profile wraps a table named profiles, which has a numeric primary key named id
SubModel wraps a table named sub_models, which has a numeric foreign key named profile_id