I have two classes:
class Post
has_and_belongs_to_many :receivers
accepts_nested_attributes_for :receivers
end
class Receiver
has_and_belongs_to_many :posts
table schema is like:
posts: id, xxx
receivers: id, email, name, xxxx
posts_receivers: post_id, receiver_id
I pretty much follows the guide here: http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
So in my post form, each one could contain several receivers, which are just several email text fields. New receiver records get created automatically from those emails. It would happen that different post form has some existing emails, then I dont want to create new records in receivers table for existing emails. Rather, I would like to find the receiver id with existing email and save the id with post id into posts_receivers table.
Now it just creates new receiver record every time for new posts, no matter the email is an existing one or a new one.
Any suggestion on how to implement this? Thanks a lot!
Nested attributes don't handle this case for you - they're more intended for when the nested objects belong to the parent object.
You can do this manually by loading up each of your existing receivers in your controller, creating the rest, then assigning them to the post:
def create
post = Post.new(params[:post])
post.receivers = params[:receivers].map do |receiver_params|
Receiver.first_or_create(receiver_params)
end
post.save!
end
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
I'm making up this example for the sake of demonstrating my issue. Let's say we have the following models:
class Case < ApplicationRecord
has_many :clients
accepts_nested_attributes_for :clients
end
class Client < ApplicationRecord
belongs_to :case
has_many :attorneys
accepts_nested_attributes_for :attorneys
end
class Attorney < ApplicationRecord
belongs_to :client
end
I'd like to add the same new attorney to different clients.
If I use params like this to update a case:
{
"clients_attributes"=>{
"0"=>{
"id"=>"1",
"attorneys_attributes"=>{
"123"=>{
"name"=>"Joe"
}
}
},
"1"=>{
"id"=>"2",
"attorneys_attributes"=>{
"456"=>{
"name"=>"Joe"
}
}
}
}
}
Rails will create two new attorney records with the same name "Joe". I'd like to just create one record and have both clients refer to it. Is there some clever was to reference an as yet uncreated record?
One thing I could do is check the params on the server side for identical names and do some post-update work. Is there an easier way?
Rails check if it's same record via the ID. Therefore, if you're using nested fields, but want to reuse the attorney record, then you need to make sure their ID are the same.
On the other hand, why do you want to use nested field? Usually you have a nested form to update the information, but for your case here.. that would means to update the attorney information under any of the client model - and updating attorney under one client, would actually affect all the same attorney under other clients.
As #DollarChills put in the comments, why not use a select field for the attorney under client, and create a separate page to update the attorney information?
Update: auto-complete solution
For the fields you feel can uniquely identify the an attorney, create a auto-complete field, based on that field. Let's take name for example
If the user put in the name match some DB record, load it and let the user select. You'll also have a create new attorney option
If user selected the attorney, just load it into the form with corresponding ID, so that your app knows who to update.
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
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 have a simple User model which is associated to many Town objects using a join table (has_and_belongs_to_many). Now I'd like to update the towns belonging to a particular user by assigning a list of comma-separated town ids (coming directly from the form sent as a HTTP POST parameter).
The user object is saved using the following controller code:
#current_object.update_attributes(params[:user])
The params[:user] includes town_ids which is, for example, set to 1,4,6.
Unfortunately, this does not update the user-town associations at all. However, if I do it manually, it works beautifully well:
User.find(:first).town_ids = "1,4,6" # this saves automatically
Could it just be that it is not possible to mass-assign these collection_singular_ids fields?
My user model contains the following:
has_and_belongs_to_many :towns
# necessary for mass-assignment, otherwise it results in an exception:
attr_accessible :town_ids
Any help is greatly appreciated.
You have to pass the town_ids as an array:
User.find(:first).update_attributes(:town_ids=>[1,4,6])
If you pass the ids as a string Rails will attempt to convert the string to an integer:
"1,4,6".to_i # => 1