I am trying to get access to a property contained inside my user object.
My user model has_many: posts. In the controller how would i gain access to these posts? Would i create a method in the model?
def posts
#posts = Post.find(User_id: params[:id])
end
or can i directly access the posts for the user. User.posts Since i am currently residing in the controller, is the controller aware of the currently selected model? Or do i have to pull the information again?
You can query the database for all the posts with a specific user_id, like this:
#posts = Post.where(user_id: params[:id])
Alternatively, you can find the user first and then fetch all posts associated with that user, like this:
user = User.find(params[:id])
#posts = user.posts
Assuming your id in params is the id of your user, you can use user = User.find(params[:id]) to get the user and #posts = user.posts to get all the posts of this user.
So, it is not about where you are, It is about what you are calling.
I'm sure you are familiar with relationships...
When you have relationships, it means that you can get to one relation from the other through whatever association exists between them.
If I am my father's son, then you can get me directly by checking my father's children. ( you don't necessarily have to get all children in the village first )
So, bringing all my story above together, with the association between your Post and User, you can always call user.posts (user being an instance of User) and post.user ( with post being an instance of Post)
The Ruby on Rails guides have a section on associations, which is what you want. It's here: http://guides.rubyonrails.org/association_basics.html
In a nutshell, because you have added an association in your user model to a number of post records, Rails will build a helper method in your user model called posts. You can use that to access all the posts associated with that user.
When you create a post, the post record needs to have a column called user_id. This will provide the 'physical' link between the user and post models. You can access the posts from a user like so:
user.posts each do |post|
# do something with post.content
end
To get posts that match some criteria in the posts collection you can query like this:
posts = user.posts.where(:something => 'matches criteria')
If you know there's only one post that matches the criteria, you can do this:
post = user.posts.where(:something => 'matches criteria').first
The post model also needs a belongs_to :user association. (The belongs_to will generate a helper method called user in the post model which you can then use to access the user record from the post.) For example:
user_email = post.user.email
The user record does not require a post_id column since Rails knows that user.post refers to the post table and automagically generates a query using user_id.
Anyway, the guide I linked to above will give you all the information you need and more too.
Related
Here's the scenario to illustrate my question. I have 2 models:
# models/post.rb
belongs_to :user
validates_presence_of :comment
And we have a devise model called Users
# models/user.rb
has_many :posts
What I would like to achieve:
Person comes to the website, is able to create a Post, after creating the Post, they are prompted to create an account. After creating the account, the Post that they just created would be associated to the User they just created.
Usually i'd make use of routes to hold the params[:id] which can be accessed in the controller method. For example the URL may look something like this:
www.foo.com/foo/new/1
And then I can do this:
# foo_controller.rb
def new
#foo = Foo.new
#parent = Parent.find(params[:id])
end
And in the view I can simply access #parent and use a hidden field to fill the parent ID.
But when routing through so many different pages (such as creating a Devise User), how do I hold onto the parent/child ID such that I can still create that association?
Using an hidden field or the route to store the id, with no authorization in the process, would not be secure. What if I just use the browser inspector and change the value of the id ? Your cool post would be mine.
What you could do is, for instance, add a field called guest_id to the Post, in which the value is unique (like SecureRandom.uuid), and also store that value in the session.
Thus, after the user is created, you could do something like that
if (post = Post.find_by(guest_id: session[:guest_id])).present?
post.update(user_id: current_user.id)
end
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
Class User
has_many :posts
end
Class Post
belongs_to :users
end
I have a post's content and would like to find out if a user ever sent a post with the same content. I could find it out easily if I was only searching against a single user.
user.posts.exists?(content: params[:content])
I would like to look through all the users in the DB.
users = Users.all
users.posts # will not work NoMethodError: undefined method `posts' for #<Array:0x007fbe818fbd98>
I need either a true as soon as there is a single match or a false if there is no user with matching content, for all the posts posted from all the users.
I could always loop this in a block and get a result this way, is there a way of doing this in a single line of code?
Try something like this:
posts = Post.where(content: params[:content])
users = User.find posts.map(&:user_id)
Or a shorter one:
users = User.find Post.where(content: params[:content]).pluck(:id)
Or if you just need to check whether a post (created by any user) with a given content exist:
Post.exists?(content: params[:content])
I have a Userand Post model with the association one-to-many. I tried to implement a repost action, add a link has_and_belongs_to_many through a table reposts.
But I was faced with the following challenges:
1) Post to feed loaded as follows:
followed_users="SELECT followed_id FROM relationships WHERE follower_id = :user ";
replics_posts="SELECT micropost_id FROM replics_users WHERE user_id = (:user)"
reposts="SELECT post_id FROM reposts WHERE user_id = (:user)"
where("user_id IN(#{followed_users}) OR user_id= (:user) OR id IN(#{replics_posts}) OR id in (#{reposts})", user: user);
and sorted by date modified. Repost similarly sorted, from which there is a situation that is repost in the middle feed.
2) No additional effort, followers do not see reposts user.
These problems can be solved through the auxiliary array with the need to fast, but it looks ridiculous and non-optimal solution.
How can I get out of the situation?
P.S. I think the solution can be found by reference in the field "Content" in the Post model on the same field, another object. Then repost action will not need a separate table and will consist only of a new Post object with a pointer to the contents of the original post. But I do not know how to do this in Ruby on Rails.
Thank you for your help!
I corrected as follows:
1) In the Post model added a new field repost_id and reference to yourself:
has_many: reposts, class_name: "Post", foreign_key: "repost_id", dependent:: destroy;
(relation to the model User not changed)
2) Added to Post's controller method repost
def repost
orig_post=Micropost.find(params[:id]);
if(orig_post)
Micropost.create(user_id:current_user.id,
content: orig_post.content,
repost_id:orig_post.id);
respond_to do |format|
format.js
end
end
end
(Do not forget to realize meets both the route and validations creation of the post)
The result is a correct model of behavior actions repost with dependencies and correct display in the feed. But sadly, this approach involves storing duplicate data in the table Posts in the "Content" field.
I've got a User model that has many Items. A Rating belongs to a User and an Item.
In the DB, I have set ratings.user_id to be not NULL.
when I am creating an Item, I would like to do this:
def create
current_user.items.create(params[:item]).ratings.create(params[:rating]
redirect_to items_path
end
However, this balks with an SQL error "user_id cannot be nil"
so I rewrote the create method as
def create
current_user.items.create(params[:item]).ratings.create(params[:rating].merge({:user_id => current_user}))
redirect_to items_path
end
which works fine.
However, I had thought that chaining the create methods off the current user's receiver would have populated the rating's user_id. Anyone know why not?
TIA.
I'd recommend you normalize this if possible in the database. Maybe take out the user_id attribute from the ratings table and if you need it in your model get it through a join using a :through method
class Rating
has_many :items
has_one :user, :through=>:items
If you created and saved the Item, then made a Rating from that item, it wouldn't pass the user along to the Rating, right? You'd just refer to it as #rating.item.user, right?
When you think about it like that, you wouldn't expect the Item created via the current_user to pass the user information along to the rating.
Make me wonder if you really need the user has_many ratings relationship.
Because Item has many Ratings and that association does not know about the user id. Given that association chain Item would have a user id because it belongs to a user. And Rating would have an item id because it belongs to an item. But the Item to Rating assocation doesn't know anything about a user unless you tell it.