Model Accepts Nesting Attributes without declaring that it accepts them - ruby-on-rails

everyone. So, I'm working on a basic Rails 4 application for practice, and I have a model for FriendCircle and a model for FriendCircleMembership. (the FriendCircleMembership's corresponding table is basically a join table).
In the console, I'm able to create a new FriendCircle object while passing in :friend_circle_memberships_attributes. This successfully inserts a new FriendCircle row into my table as well as inserting the proper rows into the FriendCircleMembership table.
The WEIRD thing is that, even if i comment out that the FriendCircle accepts_nested_attributes for :friend_circle_memberships, it still works. Is this because i am whitelisting it as a permission in the controller?
The other issue is that, even though i can successfully make the nested objects via the rails console, when i try making it through my html form it says my friend_circle_memberships_attributes is an unpermitted parameter. Not sure why this is happening. I check the incoming parameters and they look fine.
any help would be SWEEEEET. thanks.

I determined what the error was: One of my controllers for a nested attributes was validating the presence of the id of the controller it was nested under.
I'm assuming the validation occurs before an id is created, which makes sense, but im not 100%. So i just took out the validator and things worked.

Related

Rails model ignoring additional specifically selected colums from other tables

This is closely related to Rails ignores columns from second table when using .select, however that question doesn't go deep enough.
As per the above question, I have a complex query being run from one of my ActiveRecord Models which generates a kind of 'report'. It is basically a giant table of the primary Model's attributes as well as a few other attributes from related tables.
The query itself, works. I have verified that the resulting SQL executes correctly and when pasted into a SQL terminal I get the results (and columns I want). Unfortunately there is proprietary information in the models that I can't share here, and the Query is too complex to obfuscate. But To give an idea of what I am doing, this is the start of my ActiveRecord Query: permits = Permit.select('*').joins("LEFT JOIN crosstab (' ....
I have pasted the ActiveRecord Query (above) into the Rails console and not only does it execute perfectly; but the additional attributes (not asssigned to any model or association in my app) can be queried, just fine - exactly what I want:
>> permits.first.applicant_name
"Gordon Ramsay"
The problem is that when I execute the code in the rails app (executed from the browser) I can access the attributes of each permit and its associated models ok, but the additional selects on permit raise a NoMethodError.
I cannot understand why the Rails console will let me plug the commands in and work, but when I run the same code in only of my application's methods, it raises an error.
The question above seems to deal with this closely, and the accepted answer suggests trying something out in the console; but why would the console and the Rails app itself deal with this same code differently (since I am under the assumption that the Rails console is an instance of the Rails application?
Does anyone know:
Is my assumption about the ActiveRecordRelation omitting the non-model attributes correct?
Why does the Rails console allow me to do this query and call the 'extra' selected columns but Rails will not.
Is there a way I can do what I need to do - perhaps creating a proxy object or casting the Permit model to some other ActiveRecord Object that doesn't 'ignore/drop' the extra attributes from the select?

mongoid splits nested attributes in two hashes?

I've got a model List with nested attributes from another one, Article. What bugs me is I have Ruby request params having my first nested attribute in Article hash, and all the others(2nd,3rd article data, etc) in article_parameters.
I follow the standard mongoid tutorial here.
I have #list.articles.build in create method of List controller.
Can I influence what goes into build method? I've tried to call build(all_the_correct_hashes) but it does not seem to fix the issue.
So, in the nutshell I have 2 questions.
why articles gets only the first nested attribute, 2nd and next go to article_parameters hash?
why list.articles.build only creates _id in my Mongo document, but does not populate it with other fields?
I'll write up my solution, since I see people upvoting my question.
Frankly, I did not find any answer as to why such behaviour occurs.
The solution is a bit hackish.
In your save controller, call List.article.build(id => params[:id], someotherstuff => params[:someotherstuff])
Everything you pass to build in this case will populate article_parameters hash.
id and sometherstuff are fields of my Article model.
I feel this should be done implicitly by Mongoid, but it just does not work. Their development does not see anything wrong with it, either.

Rails throwing Unpermitted parameters: name error when using Devise

I am trying to follow this as an example: https://github.com/RailsApps/rails-devise/
I made a project of my own where I try it out and everything is working fine exept for the name part. If I try to make a new user or edit it, rails will throw this Unpermitted parameters: name error.
I have added name as a string into the users table and everything should be fine. I read that some people suggested adding a specific user_params mathod to allow :name but the example I linked before does not have it and in there it all works.
Also worth noting maybe that a direct INSERT INTO in pgAdmin will insert a new row with a name without any problems. So it's something with Rails.
"Unpermitted parameters" means you're doing mass assignment without marking the passed in parameter as permitted. Have another look at this section of the example app documentation: https://github.com/RailsApps/rails-devise/#adding-a-name-attribute. Make sure the name attribute is listed in config/initializers/devise_permitted_parameters.rb.

Rails 4, creating model entries by parsing xml file. Need current_user

Fairly new with rails and am digging with a new web app. I'm parsing an XML file uploaded by the user. The parsing is done with a before_save call in the upload.rb model file.
In the xml parsing function (parse_xml), my intention is to create a new model for the XML children elements and save all the attributes.
The problem I am facing is this:
As I understand, current_user is a controller helper function from devise and is not available in the models. The current model I have (Items Model containing the XML child elements) is tagged against a user_id (The current_user). The Items model does not have controllers at the moment and there is no way I can think of passing in the current_user's ID attribute into the Uploads model.
Again, to my understanding, the Uploads model works on the parse_xml function before actually running the #upload.save function in the uploads_controller.rb.
I'm not sure how to approach this problem. While I know Thread.current[:user] is suggested by a lot of people, as a learner, i prefer getting the right approach in my head rather than have a #facepalm moment when someone looks at my code :-)
Update:
Since Items records require an upload_id value, the records cannot be created until the Parent Upload record is created. Is this the reason why I also get an uninitialized constant Upload::Item error during the before_save execution in Upload#create route?
I'm not sure where things are going wrong!

Calling ActiveRecord's #relationship_ids = [1,2,3] saves immediately. Any workarounds?

I've come across an oddity in ActiveRecord's #relationship_ids method (that's added automatically when you declare 'has_many'), which saves immediately for existing records, which is causing me some issues, and I wonder if anyone had any useful advice.
I'm running Rails 2.3.5.
Consider this simple scenario, where an article has_many tags, say:
a = Article.first
a.name = "New Name" # No save yet
a.author_id = 1 # No save yet
a.tag_ids = [1,2,3] # These changes are saved to the database
# immediately, even if I don't subsequently
# call 'a.save'
This seems surprising to me. It's specifically causing problems whilst trying to build a preview facility - I want to update a bunch of attributes and then preview the article without saving it - but in this instance the tag changes do get saved, even though no other fields do.
(Of possible relevance is that if 'a' is a new article, rather than an existing one, things behave as I'd expect - nothing is saved until I call 'a.save')
I have a fairly nasty workaround - I can override the tag_ids= method in my model to instead populate an instance variable, and actually save the related models in a before_save callback.
But I'd love to know of a simpler way than me having to do this for every model with a has_many relationship I'd like to create a preview facility for.
Does anyone have any fixes/workarounds/general advice? Thanks!
There's a reason things are this way. It's called foreign keys. In a has many relationship, the information that links to the model that has many is stored outside of that model as a foreign key.
As in Articles, has many tags. The information that links a tag to an article is stored either in the tags table or in a join table. When you call save on an article you're only saving the article.
Active record modifies those other records immediately. Except in the case where you're working with a new article that hasn't been saved yet. Rails will delay creating/updating the associated records if it doesn't know which id to place in the foreign key.
However, if you're modifying existing records, the solution you've decided on is really all that you can do. There's an even uglier hack using accepts_nested_attributes_for, but it's really not worth the effort.
If you're looking to add this behaviour to many models but not all models, you might want to consider writing a simple plugin to redefine the assigment the method you need and add the call back in a single class method call. Have a look at the source of something like acts_as_audited to see how it's done.
If you're looking to add this behaviour to all models, you can probably write a wrapper for has_many to do that.

Resources