I have 3 models:
user: id
has_many :article_users
has_many :articles, through: :article_users
article: user_id
has_many :article_users
has_many :users, through: :article_users
article_user: user_id, article_id
belongs_to: users
belongs_to: articles
How to add all users id to user_id in article_user model when creating new article?
def create
#article = Article.new(article_params)
...
end
You can set a new article's user to the current user like so (assuming you have a current_user method)
#article = Article.new(article_params)
#article.user = current_user
I don't understand what you mean by "How to add all users id" - can you expand on what you actually mean by this please?
EDIT: to associate the article with all existing users, you could do something like
#article = Article.new(article_params)
#article.save
#article.users << User.all
However, this feels like an odd thing to do: it will create a lot of join table records, whereas really it could be summarised with one "bit" of information, eg "can this be accessed by all users?". What if you make a new user later - that user will not have access to this article. Do you want them to?
If you want an article to just be "available to all users" rather than "available to the following list of specific users, which might happen to be all users", then you could just add a boolean field to the Article's table called "available_to_all_users" or something. Then, when you want to find out which articles are available to a given user, you can have a method like this:
#in User
def available_articles
(Article.where(available_to_all_users: true).all + self.articles).uniq
end
There is no such way to add user_id to article_users table for existing records. You have to manually populate the user_id using a migration, but if you have user_id value in the articles table then there is a chance to add the user_id.
Related
I have a column in my database called 'email'. I want to store the current logged in user's email address into this column when they submit a specific form.
At first I thought I should write something in the html to grab the current user's email address and hide it in the form somewhere but I realized that was probably a bad idea since anyone would be able to modify the html to put any email address that they want in there.
So my question is, would I go about this in the controller? If so, how would I go about doing that?
I'm naming that other model as Article(you can use yours)
Have a column called user_id instead of email in that table
Class User
has_many :articles
end
Class Article
belongs_to :user
end
class ArticlesController
def create
#article = current_user.articles.new(article_params)
#article.save
end
def article_params
params.require(:article).permit(:field1, :field2)
end
end
If you do something like this then automatically user_id will be saved in that table.
So it will be easy for you to get all articles which is belonged to that user.
user = User.first
user.artciles # you will get all articles belonged to that user
article = Article.first
article.user # you will get user of that article
Hope this helps
Figured it out
#request.email = current_user.email
#request.save
I have two tables called
Product (prodID: integer, prodName: string, userID: FK)
and
User(userID:integer,userName:string).
The user can have many products. I want to write a query that gets me all the products for userID=10. I don't however understand which model I should put this in- the user or the product model or does it not matter? Presumably the output of the model will be fed to the controller it relies on so I should put it in the model that relates to the view I want to show it in? Is this correct?
You can directly use association method, no need of writing model method for fetching user's products.
In user.rb:
has_many :products
In product.rb
belongs_to :user
and from controller
User.where('id = ?', params[:id]).first.try(:products)
So, above query will fetch products if user with given id is found.
In your controller:
#user = User.find(params[:id])
#products = User.of_products(params[:id])
If you don't want to use #user in your action then you can avoid calculating #user.
In user.rb:
has_many :products
def self.of_products(user_id)
User.includes(:products).where(id: user_id)
end
This will give you all products of #user
This is a continuation of another question, but as it's different, I though I had better repost it as a new question:
Old Question
I'm adding quiz functionality to the twitter app from the Hartl tutorial and have these Models:
User is nearly the same as the tutorial:
class User < ActiveRecord::Base
has_many :followed_users, through: :relationships, source: :followed
has_many :takens, dependent: :destroy
has_many :questions, through: :takens
end
Taken is a table of Question ids to User ids:
class Taken < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
nothing interesting in Question:
class Question < ActiveRecord::Base
attr_accessible :category, :correct, :option1, :option2, :option3, :qn
end
I want to be able to show followed_users and followers in order of the number of tests they have taken. In the console this can be had through:
User.find_by_id(1).question_ids.count
Then I can do something like:
User.find_by_id(1).followers.first.question_ids.count
in the console to get the count for a single follower.
I feel like I'm almost there.
How do I sort the followers and followed_users through their 'takens' count? (I was also looking at cache_count, which at first seemed promising, but might not be what I need...)
End Old Question
This is the answer from the other question: rails order through count on other table
and I went with a method like this in User.rb:
def users_sort_by_taken
User.find_by_sql("SELECT users.*
SELECT users.*
FROM users INNER JOIN takens
ON users.id = takens.user_id
GROUP BY users.id
ORDER BY count(takens.user_id) DESC")
end
which gets called in the users_controller.rb like so:
def following
require 'will_paginate/array'
#title = "Following"
#user = User.find(params[:id])
##users = #user.followed_users.paginate(page: params[:page])
#users = #user.users_sort_by_taken.paginate(page: params[:page])
render 'show_follow'
end
(For reference, the commented out line is from the Hartl tutorial)
all well and good, but now the current user is contained in the list of following (because of the above SQL). I need a way to eliminate the current user from the users_sort_by_taken.
I thought this might work:
WHERE (#{#current_user.id})
in the method,but I get this error:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
I suppose I could pass it as an argument...
but don't I already have the user as #user in the following line?
#users = #user.users_sort_by_taken.paginate(page: params[:page])
Why can't I reference the current user from a method in the User.rb model?
Or another way, can I pass the current_user (or #user or user) to the SQL to exclude the current_user from the SQL results?
Any help appreciated.
Every object has its own set of instance variables - the fact that #user or #current_user is set in one object means nothing to another object.
The receiver of a method (in this case your user) is always available as self, so self.id gets you the user's id
The self is actually implicit - most of the time you won't need it and just writing id would result in the same thing (as long as you're in an instance method of that user)
To reference #user's id in the model, you can simply use:
self.id
Rails newbie... trying to understand the right way to do things...
In my app users can create a Book ( I have that working)
What I want to happen is when a user creates a book, a record is added to the BookCharacters Table, something like (id, book.id, user.id, characterdescription.string.)
When the book is created, the user who created it should automatically be added as the first BookCharacter. After than the user can then manually add/edit as many BookCharacters as they want. But initially I want them added automatically by default.
So in my Book controller I have:
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
....
With Rails, is it the practice to add that kind of logic after the book is saved? Something like
Book.create( :creator => current_user.id)
I appreciate the help
The important thing to understand is the convention by which Rails implements relationships using ActiveRecord. A book has many characters, and each character belongs to a book, so:
class Book < ActiveRecordBase
has_many :characters
end
class Character < ActiveRecordBase
belongs_to :book
end
Rails now assumes that the characters table will have a foreign key called book_id, which relates to the books table. To create a character belonging to a book:
#book = Book.new(:name=>"Book name")
#character = #book.characters.build(:name=>"Character name")
Now when #book is saved (assuming both #book and #character are valid), a row will be created in both the books and the characters tables, with the character row linked through book_id.
To show that a character also belongs to a user, you could add that relationship to the Character model:
class Character < ActiveRecordBase
belongs_to :book
belongs_to :user
end
Thus Rails now expects characters to also have foreign key called user_id, which points to a users table (which also needs a User model). To specify the user when creating the character:
#book = Book.new(:name=>"Book name")
#character = #book.characters.build(:name=>"Character name",:user=>current_user)
You can also assign the foreign key by calling the corresponding method on the object:
#character.user = current_user
This all works because it follows the Rails conventions for naming models and tables. You can depart from these conventions, but you'll have a harder time learning Rails if you do.
I prefer something like (if User has_many Book):
def create
#book = current_user.books.new(params[:book])
respond_to do |format|
if #book.save
…
I am trying to save to a join table in a habtm relationship, but I am having problems.
From my view, I pass in a group id with:
<%= link_to "Create New User", new_user_url(:group => 1) %>
# User model (user.rb)
class User < ActiveRecord::Base
has_and_belongs_to_many :user_groups
accepts_nested_attributes_for :user_groups
end
# UserGroups model (user_groups.rb)
class UserGroup < ActiveRecord::Base
has_and_belongs_to_many :users
end
# users_controller.rb
def new
#user = User.new(:user_group_ids => params[:group])
end
in the new user view, i have access to the User.user_groups object, however when i submit the form, not only does it not save into my join table (user_groups_users), but the object is no longer there. all the other objects & attributes of my User object are persistent except for the user group.
i just started learning rails, so maybe i am missing something conceptually here, but i have been really struggling with this.
Instead of using accepts_nested_attributes_for, have you considered just adding the user to the group in your controller? That way you don't need to pass user_group_id back and forth.
In users_controller.rb:
def create
#user = User.new params[:user]
#user.user_groups << UserGroup.find(group_id_you_wanted)
end
This way you'll also stop people from doctoring the form and adding themselves to whichever group they wanted.
What does your create method look like in users_controller.rb?
If you're using the fields_for construct in your view, for example:
<% user_form.fields_for :user_groups do |user_groups_form| %>
You should be able to just pass the params[:user] (or whatever it is) to User.new() and it will handle the nested attributes.
Expanding on #jimworm 's answer:
groups_hash = params[:user].delete(:groups_attributes)
group_ids = groups_hash.values.select{|h|h["_destroy"]=="false"}.collect{|h|h["group_id"]}
That way, you've yanked the hash out of the params hash and collected the ids only. Now you can save the user separately, like:
#user.update_attributes(params[:user])
and add/remove his group ids separately in one line:
# The next line will add or remove items associated with those IDs as needed
# (part of the habtm parcel)
#user.group_ids = group_ids