I've got articles that can be shown in lots of different sites. They can either be visible or not.
I've ended up going for a single bitmasked permission field in the article, rather than lots of has_many permissions separate records.
I'm not sure how best to set this field. What I've done so far is write two methods in the article model - one gives you a hash of {1 => 'true', 2 => 'true', 3 => 'false'} - visible or not on site 1, 2, 3. The second method takes a similar hash and sets the permission field correctly.
I can send the permission hash to my view through the controller, and I can make checkboxes that show if the article is visible or not. These appear on a pop up dialog using jquery. I haven't done it yet, but I think I can use javascript to make a hash to send back.
But I don't know how to make the update controller take the hash from the params, send it to my make permission method and then put that into the params again to update my article.
How would I go about doing this? Or am I barking up the wrong tree entirely.
Any ideas?
I would suggest you to create a Site model which reproduces the different sites. This is especially a good thing if there might come up more websites! Then you could build a has_and_belongs_to_many association between the Site and the Article model to commit on which site an article should be displayed!
Related
I have a controller without a model that handles a very cyclical task.
The user is basically filling out a form, sending it up to the server for some minor analysis, and then the server regurgitates nearly the same thing back to the user.
The user makes some adjustments, and the process starts over again.
There is nothing to save or store from this process, so it doesn't have a model.
The form i am working with has a large number of fields to deal with. Is there a way I can pass the params hash back into the view with the least amount of mess getting the fields repopulated?
Basically, I would want to tweak a couple of values in the params hash, but more or less pass the hash back so that it can repopulate the view nearly exactly how it was when it was submitted.
The old way of using OpenStruct seemed ideal.
Will this help?
In controller action, just initialize a variable like #params (or some thing like this), so that can be able to use all the values in the params can be available in that view page.
Maybe an ActiveForm is good for your application. It use to manage (new/create/validate/...) forms with no or several models.
https://github.com/realityforge/rails-active-form
First, here is the code: http://pastie.org/5448967
Now, here is the scenario:
I have a project object - don't worry about the attachment batches as I have not implemented a solution for those yet - which has associated analysis requests of which there are set options of analyses. That is, there is a table of analyses which the user can choose from and for each one chosen an analysis request is created that links the analysis to the project.
Here's the problem:
When attempting to update the analysis requests the first thing that I notice is a problem with the parameters from the form not "hashing" as I would expect.
Here's what I want:
params={:projects=>{"#{project_id}"=>{project_attribute, project_attribute, etc..., analysisrequests=>[array,of,analysis,ids]}, "#{project_id}"=>{project_attribute, project_attribute, etc..., analysisrequests=>[array,of,analysis,ids]}, ...}
Here's what I get:
{"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"XfIr7zfVNdlg5HS3Letw4sI/MGNFTtqntQYrgjAh9TY=", "project"=>{"1832"=>{"project_number"=>"261", "nof_samples"=>"5", "analysisrequest"=>{"analysis_id"=>["", "8",
"12"]}}, "status_id"=>"13", "rush_service"=>"0", "customer_id"=>"111", "project_notes"=>"test", "sample_desc"=>"test", "user_id"=>"1", "quoted_price"=>"1", "1834"=>{"project_number"=>"777", "nof_samples"=>"1", "analysisrequest"=>{"analysis_id"=>["", "3", "9", "20", "22"]}}}, "commit"=>"Submit Changes"}
Stating the obvious:
I'm not too worried about changing "analysisrequest"=>{"analysis_id"=>["", "8", ...]} to "analysisrequest"=>["", "8", ...] or "analysisrequests"=>[] (note the s). In fact, I've done this so as to render a single multi-select in the form rather than a multi-select for each request associated with the project (which it does if you add the 's') - the "analysis_id" nesting is fine as well as you can see that each request could have "analysisrequest"=>{"analysis_id"=>[],"project_id"=>[]} so that's obviously Rails doing its job.
The most important of my concerns is that the additional parameters seen after the analysis requests in the first project in the hash are not appearing after the second. That, and, that these additional parameters are not within the hash keyed by "#{project_id}" and, are, instead, outside of it in their own little world. This makes it very difficult for me to update by doing something like:
params[:projects].keys.each do |project_id|
'update entries based on project_id'
end
Is there anyone out there who might be able to give me some expert advice on this matter? I'm willing to exchange my IT or chemical services for your advice (I work in a lab) because I need to get this up and working.
Thanks for reading,
-Adam
tl;dr - Form is not "hashing" the attributes in the form in the way that I think it should.
--EDITS--
11/29/2012 - I've still been unable to understand why the parameters hash is being skewed the way it is but, I've come up with a reasonable workaround if I can figure out how to do one thing: configure a delete option via formtastic or my own methods. That is, already through the creation form for a project am I able to create as many analysis requests as needed it's just that now I would need a way to add and remove them through the edit form. I can see an option within the collection being set to "Delete" with the database id working with a method at the controller level; however, what is more pressing is being able to add additional requests in the form which I have not yet been able to achieve via Rails 3.2.1. I know that it works in 2.3.5 but, so far, it hasn't been working for my configuration. I'll post more as I find out.
+2 hours (later) - Implemented Ryan Bates' ep.197 methods for removing fields so far; but, I've run into some kind of gotcha where either formtastic or my model has no idea what to do with the _destroy field even though I set the :allow_destroy => true. Perhaps it has to do with the placement of the link? Here's the code for my newest form (the js and application helper code are as they can be seen here): http://pastie.org/5454653
Check out this: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
Perhaps you should have these routes:
resources :projects do
collection do
get 'edit', action: 'edit_collection'
put 'update_collection'
end
end
Don't forget to define a update_collection method in the controller.
Just a note you can use class instances in edit_collection.html.erb instead of rendering the page and passing in the local.
For instance:
<% #projects.each do |project| %>
instead of
<% for project in projects %>
So I'm writing a Facebook clone for a school project using Rails and I need some way to keep track of which users are logged in. At the moment, I'm a bit time-pressed, so I decided just to update the User model every time they visit a page with a last_seen attribute.
Problem is, the user model requires revalidation to successfully update_attributes. So I'm wondering two things:
Is there a better way to do this that I'm missing?
If not (or if it would take too long) is there a way to bypass the validation?
to 1.: I cant give you an exact answer but I think itwould be better to deal with this problem using a javascript on the clientside with a timer that sends an ajax request all xxx secounds and an action that receives this requests and saves it in a seperate table associated with the User.
to 2.: Yes there are some ways to bypass validations The most pragmatic way is to bypass the :validate => false option when saving the object but then you can use update_attributes:
object.save(:validate => false)
So there is also the possibility to use conditional validations that are only used when a specific condition is complyed. There is a railscast about that => http://railscasts.com/episodes/41-conditional-validations .
So lets say I have a form for submitting a new post.
The form has a hidden field which specify's the category_id. We are also on the show view for that very category.
What I'm worried about, is that someone using something like firebug, might just edit the category id in the code, and then submit the form - creating a post for a different category.
Obviously my form is more complicated and a different scenario - but the idea is the same. I also cannot define the category in the post's create controller, as the category will be different on each show view...
Any solutions?
EDIT:
Here is a better question - is it possible to grab the Category id in the create controller for the post, if its not in a hidden field?
Does your site have the concept of permissions / access control lists on the categories themselves? If the user would have access to the other category, then I'd say there's no worry here since there's nothing stopping them from going to that other category and doing the same.
If your categories are restricted in some manner, then I'd suggest nesting your Post under a category (nested resource routes) and do a before_filter to ensure you're granted access to the appropriate category.
config/routes.rb
resources :categories do
resources :posts
end
app/controllers/posts_controller
before_filter :ensure_category_access
def create
#post = #category.posts.new(params[:post])
...
end
private
def ensure_category_access
#category = Category.find(params[:category_id])
# do whatever you need to do. if you don't have to validate access, then I'm not sure I'd worry about this.
# If the user wants to change their category in their post instead of
# going to the other category and posting there, I don't think I see a concern?
end
URL would look like
GET
/categories/1/posts/new
POST
/categories/1/posts
pst is right- never trust the user. Double-check the value sent via the view in your controller and, if it does't match something valid, kick the user out (auto-logout) and send the admin an email. You may also want to lock the user's account if it keeps happening.
Never, ever trust the user, of course ;-)
Now, that being said, it is possible to with a very high degree of confidence rely on hidden fields for temporal storage/staging (although this can generally also be handled entirely on the server with the session as well): ASP.NET follows this model and it has proven to be very secure against tampering if used correctly -- so what's the secret?
Hash validation aka MAC (Message Authentication Code). The ASP.NET MAC and usage is discussed briefly this article. In short the MAC is a hash of the form data (built using a server -- and perhaps session -- secret key) which is embedded in the form as a hidden field. When the form submission occurs this MAC is re-calculated from the data and then compared with the original MAC. Because the secrets are known only to the server it is not (realistically) possible for a client to generate a valid MAC from the data itself.
However, I do not use RoR or know what modules, if any, may implement security like this. I do hope that someone can provide more insight (in their own answer ;-) if such solutions exist, because it is a very powerful construct and easily allows safe per-form data association and validation.
Happy coding.
This is probably really simple but I have a nested resource lets say:
map. resources :book, :has_many => :pages
I write an action called "turn" that increases page.count by 1. How do I call this action using a link_to? Thanks a lot in advance.
It's hard to tell where your page.count comes in. In Railish, you would find pages.count (note the 's'). Further, count (and also size) is a read-only attribute on arrays and hashes et.al. provided by ruby that returns the number of elements. You don't set count.
Next, I'm not sure where your turn action is supposed to live, on the Book or the Page? And what is supposed to happen after it does what it does? Finally, a route is what makes an action an action -- without it, it's just a function.
For a moment, we'll assume you are trying to store the number of times a Page in a Book has been visited. It would be a better idea to have an instance variable called reads or times_viewed etc. in your Page model. Assuming your Book model is using restful routing, in Book's show action, you create an instance variable of the Page model being viewed and increment its reads attribute before rendering the view.
If you are trying to make a link sort of how 'Like' works in Facebook, meaning you want to update a record in a table without sending the user to a different page, you'll need to use link_to_remote* and some javascript. In that case, I'd just refer you to the Railscasts on that subject.
*I think as of Rails 3, link_to_remote became just link_to with :remote => true.