Rails: For each Array giving Error? - ruby-on-rails

In one form I am creating a territory and editing multiple users. The "user_attributes" below are for the users and the "name" is for the territory. So for each user_attribute I wanted to update the user model.
params
{ "territory"=>{"name"=>"Central Canada",
"user_attributes"=>[{"user_id"=>"30"},{"user_id"=>"30"}]}
}
create action
#territory = #current_account.territories.new[:territory]
params[:user_attributes].each do |item|
#user = User.find(item[:user_id])
#user.update_attribute(:territory_id, #territory.id)
end
But rails is kicking back that params[:user_attributes] is nil. But you can see from the params its not. Am I missing something??

From what you posted, your user_attributes hash is INSIDE your territory hash. That should be your problem -- either move it outside, or do params[:territory][:user_attributes]

Try params["user_attributes"].

Related

change params value before patch

I have a texfield in a form where a foreign key's value is displayed. now I want to update the value and save it to the DB. Here is the code:
for the form I use:
f.text_field :port, :value =>#entry.port.number, class:"form-
control", placeholder:"Port"
in the controller I am using a param method:
def entry_params
params.require(:entry).permit(:description,:rule_id, :protocol_id,
:url, :port)
end
the update method looks like this:
def update
#entry.url.name = params[:entry][:url]
#entry.port.number = params[:entry][:port]
if #entry.update(entry_params)
flash[:success] = "Entry was successfully updated!"
redirect_to entry_path(#entry)
else
render 'edit'
end
end
but if I want try to save it, it shows this error:
Url(#70247237379440) expected, got "www.drive.google.com" which is an
instance of String(#70247218839280)
Now my question is, (I'm relativ new to rails) how can I fix this? I know that it expect an object as a parameter but if I change the param like this:
params[:url] = #entry.url
it doesn't work.
There are two approaches I can think of here, depending on exactly what you're looking to achieve.
If you're looking to assign an entry a new url based on a string params, you can use something like the following:
#entry.url = Url.find_by_name(params[:entry][:url])
Depending on your models' setup, if there's a url_id column on your entries, you might be better off using a select field on this, passing the URL's name and id to the options. If you can add this info to your question, I can update / rule this out as needed.
If you're just looking to update the URL via the entry's form, you'd be best looking at using accepts_nested_attributes_for.
Doing this, you can directly update the associated objects through the parent's form. If this sounds like the right approach for you, let me know and I can provide more detail :)
Edit: as per your comment, is sounds like this is the option you're after. So, you'd need something like the following:
entry.rb
accepts_nested_attributes_for :url
In the form:
...
f.nested_fields_for :url do |url_fields|
url_fields.text_field :name
end
...
And you'll need to update the params in your controller to accept these nested fields. I can't remember the exact for they take, but it's something like:
def new / edit # whichever you're in
...
#entry.build_url unless #entry.url.present?
end
def entry_params
params.require(:entry).permit(:description,:rule_id, :protocol_id,
:port, url_attributes: [:name])
end
(It might be you need an empty array or a hash for url_attributes.)
That'll then directly update the associated url. FYI if you've not got an associated URL, you'll need to build one using #entry.build_url in the controller.
Hope this helps - if you've any questions / details to help clarify, let me know and I'll update as needed.

Adding a parameter to an instance variable in Rails

I am creating a instance variable that gets passed to my view. This variable 'post' has a user_id associated with it and I wanted to add an extra attribute called 'username' so I can also pass that and use it in the view.
Here is an example of what I would like to do.
#post = Post.find(params[:id])
#post.username = User.find(#post.user_id).username
A username column does exist on my Users model but not my Songs model. So it won't let me use
#post.username
I know I can just make an entirely new instance variable and put that information in there but I would like to keep everything nice and neat, in one variable. Which will also make my json rendered code look cleaner.
Any ideas on how I can accomplish this?
Thanks!
Based on the presence of a user_id in your Post model, you probably already have an association set up that can retrieve the username. It will probably save a lot of trouble to simply use the existing association:
#post = Post.find(params[:id])
username = #post.user.username
If you're likely to be querying more than one post at a time (e.g., on an index page, calling .includes to tell Rails to eager-load an association will help you avoid the N+1 problem:
#posts = Post.includes(:user).all
Finally, to include the associated record in your JSON output, pass the :include parameter as you serialize:
# in controller
render :json => #post.to_json(:include => :user)
This question includes a much more comprehensive discussion of serialization options. Well worth a read.
No need to pass a separate instance variable.
1. You can use #post.user.username in view itself.
2. Or you can create a helper and pass #post.user
def username user
user.username
end

a simple thing to ask regards to update an instance with 'params'

I am using Rails v2.3.2.
If :
params[:car]={"name"=>"mycar", "brand"=>"toyota"}
I tried to udpate a #car instance by:
#car.update_attributes(params[:car])
but the #car is not updated.
Why I can not update like this? Do I must update the #car by specify each filed like following:
#car.update_attributes(:name=>params[:car][:name], :brand=>params[:car][:brand])
instead of update with the params[:car] as a whole like:
#car.update_attributes(params[:car])
Anyone can explain to me?
P.S. the params is:
{"commit"=>"Save", "authenticity_token"=>"w/d2uI/2tK9vSZvtF9oQDjY5iBPL8fji33IZcpm9cY0=", "_method"=>"put", "action"=>"update", "id"=>"4", "controller"=>"cars", "car"=>{"name"=>"mycar", "brand"=>"toyota"}
No, never update an object like this:
#car.update_attributes(:name=>params[:car][:name], :brand=>params[:car][:brand])
This is wrong. This would only be useful if you only want to update these attributes.
Always use this instead:
#car.update_attributes(params[:car])
Assuming your params don't have anything more in them besides name and brand then these two statements are identical.
What you're doing in the first one is that you're building this hash:
{ :name => "mycar", :brand => "Toyota" }
And in the second one, you're passing through a hash that is basically identical, with the only difference being the object's id.
As for why the object is not saving, try calling update_attributes and then call .errors on the object after that and that will return any validation errors that were encountered when saving.

How do I reject if exists? for non-nested attributes?

Currently my controller lets a user submit muliple "links" at a time. It collects them into an array, creates them for that user, but catches any errors for the User to go back and fix. How can I ignore the creation of any links that already exist for that user? I know that I can use validates_uniqueness_of with a scope for that user, but I'd rather just ignore their creation completely. Here's my controller:
#links =
params[:links].values.collect{ |link|
current_user.links.create(link)
}.reject { |p| p.errors.empty? }
Each link has a url, so I thought about checking if that link.url already exists for that user, but wasn't really sure how, or where, to do that. Should I tack this onto my controller somehow? Or should it be a new method in the model, like as in a before_validation Callback? (Note: these "links" are not nested, but they do belong_to :user.)
So, I'd like to just be able to ignore the creation of these links if possible. Like if a user submits 5 links, but 2 of them already exist for him, then I'd just like for those 2 to be ignored, while the other 3 are created. How should I go about doing this?
Edit: Thanks to Kandada, I'm now using this:
#links =
params[:links].values.collect.reject{
|link|
current_user.links.exists?(:url=>link[:url])}
#links = #links.collect{ |link|
current_user.links.create(link)
}.reject { |p| p.errors.empty? }
So I separated the two, to first check if there are any that exist, then to create those that weren't rejected. Is there a better way to do this, like maybe combining the two statements would increase performance? If not, I think I'm pretty satisfied. (thank you again Kandada and j.)
Try this:
#links = current_user.links.create(params[:links].reject{ |link|
current_user.links.exists?(:url=>link[:url]) })
Alternatively you can add an uniqueness check in the Link model for the url attribute.
class Link
validates_uniqueness_of :url, :scope => [:user_id]
end
In your controller:
#links = current_user.links.create(params[:links])
The result set returned is an array of newly created Link objects. Any links matching the existing links are ignored.
Edit
Here is another way to do this in one pass.
#links = params[:links].map{|link|
!current_user.links.exists?(:url=> link[:url]) and
current_user.links.create(link)}.select{|link| link and
link.errors.empty?}
I still think you should get your unique validation working and use this code afterwards:
#links = current_user.links.create(params[:links]).select{|link|
link.errors.empty?}
In the latter approach uniqueness validation is done in the model. This ensures link url uniqueness regardless how the link is created.
Reject the existent links before create them:
new_links = params[:links].reject{ |link| current_user.links.exists?(link) }
Somethink like this. Not sure about this code...

Rails: modify form parameters before modifying the database

I'm working on a Rails app that sends data through a form. I want to modify some of the "parameters" of the form after the form sends, but before it is processed.
What I have right now
{"commit"=>"Create",
"authenticity_token"=>"0000000000000000000000000"
"page"=>{
"body"=>"TEST",
"link_attributes"=>[
{"action"=>"Foo"},
{"action"=>"Bar"},
{"action"=>"Test"},
{"action"=>"Blah"}
]
}
}
What I want
{"commit"=>"Create",
"authenticity_token"=>"0000000000000000000000000"
"page"=>{
"body"=>"TEST",
"link_attributes"=>[
{"action"=>"Foo",
"source_id"=>1},
{"action"=>"Bar",
"source_id"=>1},
{"action"=>"Test",
"source_id"=>1},
{"action"=>"Blah",
"source_id"=>1},
]
}
}
Is this feasible? Basically, I'm trying to submit two types of data at once ("page" and "link"), and assign the "source_id" of the "links" to the "id" of the "page."
Before it's submitted to the database you can write code in the controller that will take the parameters and append different information before saving. For example:
FooController < ApplicationController
def update
params[:page] ||= {}
params[:page][:link_attributes] ||= []
params[:page][:link_attriubtes].each { |h| h[:source_id] ||= '1' }
Page.create(params[:page])
end
end
Edit params before you use strong params
Ok, so (reviving this old question) I had a lot of trouble with this, I wanted to modify a param before it reached the model (and keep strong params). I finally figured it out, here's the basics:
def update
sanitize_my_stuff
#my_thing.update(my_things_params)
end
private
def sanitize_my_stuff
params[:my_thing][:my_nested_attributes][:foo] = "hello"
end
def my_things_params
params.permit(etc etc)
end
You should also probably look at callbacks, specifically before_validate (if you're using validations), before_save, or before_create.
It's hard to give you a specific example of how to use them without knowing how you're saving the data, but it would probably look very similar to the example that Gaius gave.

Resources